提交 0fdcbd1d 编写于 作者: C Carol Eidt

Eliminate gtLsraInfo from GenTree

Generate TreeNodeInfo into the map when building RefPositions.
Add some new methods and flags for former gtLsraInfo functionality that's used outside of LSRA:
- GenTree::GetRegisterDstCount() (number of registers defined by a node)
- LIR::Flags::RegOptional
- gtDebugFlags::GTF_DEBUG_NODE_LSRA_ADDED

Fix dotnet/coreclr#7255


Commit migrated from https://github.com/dotnet/coreclr/commit/4157555a94ee1d0fe9831bef12d39fed1ac7d1cf
上级 bca754a4
......@@ -10070,11 +10070,13 @@ void emitter::emitDispImm(ssize_t imm, bool addComma, bool alwaysHex /* =false *
printf("#");
}
// Munge any pointers if we want diff-able disassembly
// Munge any pointers if we want diff-able disassembly.
// Since some may be emitted as partial words, print as diffable anything that has
// significant bits beyond the lowest 8-bits.
if (emitComp->opts.disDiffable)
{
ssize_t top44bits = (imm >> 20);
if ((top44bits != 0) && (top44bits != -1))
ssize_t top56bits = (imm >> 8);
if ((top56bits != 0) && (top56bits != -1))
imm = 0xD1FFAB1E;
}
......
......@@ -764,6 +764,61 @@ bool GenTree::gtHasReg() const
return hasReg;
}
//-----------------------------------------------------------------------------
// GetRegisterDstCount: Get the number of registers defined by the node.
//
// Arguments:
// None
//
// Return Value:
// The number of registers that this node defines.
//
// Notes:
// This should not be called on a contained node.
// This does not look at the actual register assignments, if any, and so
// is valid after Lowering.
//
int GenTree::GetRegisterDstCount() const
{
assert(!isContained());
if (!IsMultiRegNode())
{
return (IsValue()) ? 1 : 0;
}
else if (IsMultiRegCall())
{
// temporarily cast away const-ness as AsCall() method is not declared const
GenTree* temp = const_cast<GenTree*>(this);
return temp->AsCall()->GetReturnTypeDesc()->GetReturnRegCount();
}
else if (IsCopyOrReloadOfMultiRegCall())
{
// A multi-reg copy or reload, will have valid regs for only those
// positions that need to be copied or reloaded. Hence we need
// to consider only those registers for computing reg mask.
GenTree* tree = const_cast<GenTree*>(this);
GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload();
GenTreeCall* call = copyOrReload->gtGetOp1()->AsCall();
return call->GetReturnTypeDesc()->GetReturnRegCount();
}
#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
else if (OperIsPutArgSplit())
{
return (const_cast<GenTree*>(this))->AsPutArgSplit()->gtNumRegs;
}
// A PUTARG_REG could be a MultiRegOp on ARM since we could move a double register to two int registers,
// either for all double parameters w/SoftFP or for varargs).
else
{
assert(OperIsMultiRegOp());
return (TypeGet() == TYP_LONG) ? 2 : 1;
}
#endif // !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
assert(!"Unexpected multi-reg node");
return 0;
}
//---------------------------------------------------------------
// gtGetRegMask: Get the reg mask of the node.
//
......@@ -16065,19 +16120,6 @@ bool Compiler::gtComplexityExceeds(GenTreePtr* tree, unsigned limit)
}
}
// -------------------------------------------------------------------------
// IsRegOptional: Returns true if this gentree node is marked by lowering to
// indicate that codegen can still generate code even if it wasn't allocated
// a register.
bool GenTree::IsRegOptional() const
{
#ifdef LEGACY_BACKEND
return false;
#else
return gtLsraInfo.regOptional;
#endif
}
bool GenTree::IsPhiNode()
{
return (OperGet() == GT_PHI_ARG) || (OperGet() == GT_PHI) || IsPhiDefn();
......
......@@ -680,6 +680,8 @@ public:
void CopyReg(GenTreePtr from);
bool gtHasReg() const;
int GetRegisterDstCount() const;
regMaskTP gtGetRegMask() const;
unsigned gtFlags; // see GTF_xxxx below
......@@ -702,10 +704,6 @@ public:
regMaskSmall gtUsedRegs; // set of used (trashed) registers
#endif // LEGACY_BACKEND
#ifndef LEGACY_BACKEND
TreeNodeInfo gtLsraInfo;
#endif // !LEGACY_BACKEND
void SetVNsFromNode(GenTreePtr tree)
{
gtVNPair = tree->gtVNPair;
......@@ -1022,8 +1020,9 @@ public:
#define GTF_DEBUG_NODE_LARGE 0x00000004
#define GTF_DEBUG_NODE_CG_PRODUCED 0x00000008 // genProduceReg has been called on this node
#define GTF_DEBUG_NODE_CG_CONSUMED 0x00000010 // genConsumeReg has been called on this node
#define GTF_DEBUG_NODE_LSRA_ADDED 0x00000020 // This node was added by LSRA
#define GTF_DEBUG_NODE_MASK 0x0000001F // These flags are all node (rather than operation) properties.
#define GTF_DEBUG_NODE_MASK 0x0000003F // These flags are all node (rather than operation) properties.
#define GTF_DEBUG_VAR_CSE_REF 0x00800000 // GT_LCL_VAR -- This is a CSE LCL_VAR node
#endif // defined(DEBUG)
......@@ -1133,10 +1132,20 @@ public:
}
}
// NOTE: the three UnusedValue helpers immediately below are defined in lir.h.
// LIR flags
// These helper methods, along with the flag values they manipulate, are defined in lir.h
//
// UnusedValue indicates that, although this node produces a value, it is unused.
inline void SetUnusedValue();
inline void ClearUnusedValue();
inline bool IsUnusedValue() const;
// RegOptional indicates that codegen can still generate code even if it isn't allocated a register.
inline bool IsRegOptional() const;
inline void SetRegOptional();
inline void ClearRegOptional();
#ifdef DEBUG
void dumpLIRFlags();
#endif
bool OperIs(genTreeOps oper) const
{
......@@ -2135,17 +2144,6 @@ public:
inline var_types CastFromType();
inline var_types& CastToType();
// Returns true if this gentree node is marked by lowering to indicate
// that codegen can still generate code even if it wasn't allocated a
// register.
bool IsRegOptional() const;
#ifndef LEGACY_BACKEND
void ClearRegOptional()
{
gtLsraInfo.regOptional = false;
}
#endif
// Returns "true" iff "this" is a phi-related node (i.e. a GT_PHI_ARG, GT_PHI, or a PhiDefn).
bool IsPhiNode();
......
......@@ -1763,3 +1763,10 @@ void LIR::InsertBeforeTerminator(BasicBlock* block, LIR::Range&& range)
blockRange.InsertBefore(insertionPoint, std::move(range));
}
#ifdef DEBUG
void GenTree::dumpLIRFlags()
{
JITDUMP("[%c%c%c]", IsUnusedValue() ? 'U' : '-', IsRegOptional() ? 'O' : '-');
}
#endif
......@@ -38,6 +38,9 @@ public:
// that this bit should not be assumed to be valid
// at all points during compilation: it is currently
// only computed during target-dependent lowering.
RegOptional = 0x04, // Set on a node if it produces a value, but does not
// require a register (i.e. it can be used from memory).
};
};
......@@ -327,4 +330,19 @@ inline bool GenTree::IsUnusedValue() const
return (gtLIRFlags & LIR::Flags::UnusedValue) != 0;
}
inline void GenTree::SetRegOptional()
{
gtLIRFlags |= LIR::Flags::RegOptional;
}
inline void GenTree::ClearRegOptional()
{
gtLIRFlags &= ~LIR::Flags::RegOptional;
}
inline bool GenTree::IsRegOptional() const
{
return (gtLIRFlags & LIR::Flags::RegOptional) != 0;
}
#endif // _LIR_H_
......@@ -4747,19 +4747,19 @@ bool Lowering::LowerUnsignedDivOrMod(GenTreeOp* divMod)
// node - pointer to the DIV or MOD node
//
// Returns:
// The next node to lower.
// nullptr if no transformation is done, or the next node in the transformed node sequence that
// needs to be lowered.
//
GenTree* Lowering::LowerConstIntDivOrMod(GenTree* node)
{
assert((node->OperGet() == GT_DIV) || (node->OperGet() == GT_MOD));
GenTree* next = node->gtNext;
GenTree* divMod = node;
GenTree* dividend = divMod->gtGetOp1();
GenTree* divisor = divMod->gtGetOp2();
if (!divisor->IsCnsIntOrI())
{
return next; // no transformations to make
return nullptr; // no transformations to make
}
const var_types type = divMod->TypeGet();
......@@ -4770,7 +4770,7 @@ GenTree* Lowering::LowerConstIntDivOrMod(GenTree* node)
// We shouldn't see a divmod with constant operands here but if we do then it's likely
// because optimizations are disabled or it's a case that's supposed to throw an exception.
// Don't optimize this.
return next;
return nullptr;
}
ssize_t divisorValue = divisor->gtIntCon.IconValue();
......@@ -4786,7 +4786,7 @@ GenTree* Lowering::LowerConstIntDivOrMod(GenTree* node)
// case so optimizing this case would break C# code.
// A runtime check could be used to handle this case but it's probably too rare to matter.
return next;
return nullptr;
}
bool isDiv = divMod->OperGet() == GT_DIV;
......@@ -4798,8 +4798,7 @@ GenTree* Lowering::LowerConstIntDivOrMod(GenTree* node)
// If the divisor is the minimum representable integer value then we can use a compare,
// the result is 1 iff the dividend equals divisor.
divMod->SetOper(GT_EQ);
ContainCheckCompare(divMod->AsOp());
return next;
return node;
}
}
......@@ -4810,7 +4809,7 @@ GenTree* Lowering::LowerConstIntDivOrMod(GenTree* node)
{
if (comp->opts.MinOpts())
{
return next;
return nullptr;
}
#if defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
......@@ -4921,7 +4920,7 @@ GenTree* Lowering::LowerConstIntDivOrMod(GenTree* node)
return mulhi;
#else
// Currently there's no GT_MULHI for ARM32
return next;
return nullptr;
#endif
}
......@@ -4929,7 +4928,7 @@ GenTree* Lowering::LowerConstIntDivOrMod(GenTree* node)
LIR::Use use;
if (!BlockRange().TryGetUse(node, &use))
{
return next;
return nullptr;
}
// We need to use the dividend node multiple times so its value needs to be
......@@ -5030,13 +5029,14 @@ GenTree* Lowering::LowerSignedDivOrMod(GenTreePtr node)
if (!varTypeIsFloating(node->TypeGet()))
#endif // _TARGET_XARCH_
{
next = LowerConstIntDivOrMod(node);
}
if ((node->OperGet() == GT_DIV) || (node->OperGet() == GT_MOD))
{
ContainCheckDivOrMod(node->AsOp());
// LowerConstIntDivOrMod will return nullptr if it doesn't transform the node.
GenTree* newNode = LowerConstIntDivOrMod(node);
if (newNode != nullptr)
{
return newNode;
}
}
ContainCheckDivOrMod(node->AsOp());
return next;
}
......@@ -5890,7 +5890,7 @@ void Lowering::ContainCheckDivOrMod(GenTreeOp* node)
{
// If there are no containable operands, we can make an operand reg optional.
// SSE2 allows only divisor to be a memory-op.
SetRegOptional(divisor);
divisor->SetRegOptional();
}
return;
}
......@@ -5912,7 +5912,7 @@ void Lowering::ContainCheckDivOrMod(GenTreeOp* node)
{
// If there are no containable operands, we can make an operand reg optional.
// Div instruction allows only divisor to be a memory op.
SetRegOptional(divisor);
divisor->SetRegOptional();
}
#endif // _TARGET_XARCH_
}
......
......@@ -224,22 +224,6 @@ private:
bool IsCallTargetInRange(void* addr);
#if defined(_TARGET_XARCH_)
//----------------------------------------------------------------------
// SetRegOptional - sets a bit to indicate to LSRA that register
// for a given tree node is optional for codegen purpose. If no
// register is allocated to such a tree node, its parent node treats
// it as a contained memory operand during codegen.
//
// Arguments:
// tree - GenTree node
//
// Returns
// None
void SetRegOptional(GenTree* tree)
{
tree->gtLsraInfo.regOptional = true;
}
GenTree* PreferredRegOptionalOperand(GenTree* tree);
// ------------------------------------------------------------------
......@@ -273,13 +257,18 @@ private:
const bool op1Legal = tree->OperIsCommutative() && (operatorSize == genTypeSize(op1->TypeGet()));
const bool op2Legal = operatorSize == genTypeSize(op2->TypeGet());
GenTree* regOptionalOperand = nullptr;
if (op1Legal)
{
SetRegOptional(op2Legal ? PreferredRegOptionalOperand(tree) : op1);
regOptionalOperand = op2Legal ? PreferredRegOptionalOperand(tree) : op1;
}
else if (op2Legal)
{
SetRegOptional(op2);
regOptionalOperand = op2;
}
if (regOptionalOperand != nullptr)
{
regOptionalOperand->SetRegOptional();
}
}
#endif // defined(_TARGET_XARCH_)
......
......@@ -472,8 +472,6 @@ void Lowering::LowerPutArgStk(GenTreePutArgStk* putArgStk)
head->gtSeqNum = fieldList->gtSeqNum;
#endif // DEBUG
head->gtLsraInfo = fieldList->gtLsraInfo;
BlockRange().InsertAfter(fieldList, head);
BlockRange().Remove(fieldList);
......@@ -515,7 +513,7 @@ void Lowering::LowerPutArgStk(GenTreePutArgStk* putArgStk)
LclVarDsc* varDsc = &(comp->lvaTable[fieldNode->AsLclVarCommon()->gtLclNum]);
if (!varDsc->lvDoNotEnregister)
{
SetRegOptional(fieldNode);
fieldNode->SetRegOptional();
}
else
{
......@@ -533,7 +531,7 @@ void Lowering::LowerPutArgStk(GenTreePutArgStk* putArgStk)
// than spilling, but this situation is not all that common, as most cases of promoted
// structs do not have a large number of fields, and of those most are lclVars or
// copy-propagated constants.
SetRegOptional(fieldNode);
fieldNode->SetRegOptional();
}
}
......@@ -1655,12 +1653,12 @@ void Lowering::ContainCheckMul(GenTreeOp* node)
// Has a contained immediate operand.
// Only 'other' operand can be marked as reg optional.
assert(other != nullptr);
SetRegOptional(other);
other->SetRegOptional();
}
else if (hasImpliedFirstOperand)
{
// Only op2 can be marke as reg optional.
SetRegOptional(op2);
op2->SetRegOptional();
}
else
{
......@@ -1779,7 +1777,7 @@ void Lowering::ContainCheckCast(GenTreeCast* node)
{
// Mark castOp as reg optional to indicate codegen
// can still generate code if it is on stack.
SetRegOptional(castOp);
castOp->SetRegOptional();
}
}
}
......@@ -1854,7 +1852,7 @@ void Lowering::ContainCheckCompare(GenTreeOp* cmp)
{
// SSE2 allows only otherOp to be a memory-op. Since otherOp is not
// contained, we can mark it reg-optional.
SetRegOptional(otherOp);
otherOp->SetRegOptional();
}
return;
......@@ -1875,7 +1873,7 @@ void Lowering::ContainCheckCompare(GenTreeOp* cmp)
}
else
{
SetRegOptional(op1);
op1->SetRegOptional();
}
}
}
......@@ -1894,14 +1892,14 @@ void Lowering::ContainCheckCompare(GenTreeOp* cmp)
}
else if (op1->IsCnsIntOrI())
{
SetRegOptional(op2);
op2->SetRegOptional();
}
else
{
// One of op1 or op2 could be marked as reg optional
// to indicate that codegen can still generate code
// if one of them is on stack.
SetRegOptional(PreferredRegOptionalOperand(cmp));
PreferredRegOptionalOperand(cmp)->SetRegOptional();
}
}
}
......@@ -2142,7 +2140,7 @@ void Lowering::ContainCheckBoundsChk(GenTreeBoundsChk* node)
else
{
// We can mark 'other' as reg optional, since it is not contained.
SetRegOptional(other);
other->SetRegOptional();
}
}
}
......@@ -2167,7 +2165,7 @@ void Lowering::ContainCheckIntrinsic(GenTreeOp* node)
{
// Mark the operand as reg optional since codegen can still
// generate code if op1 is on stack.
SetRegOptional(op1);
op1->SetRegOptional();
}
}
}
......
此差异已折叠。
此差异已折叠。
......@@ -38,22 +38,25 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// Return Value:
// None.
//
void LinearScan::TreeNodeInfoInitReturn(GenTree* tree)
void LinearScan::TreeNodeInfoInitReturn(GenTree* tree, TreeNodeInfo* info)
{
TreeNodeInfo* info = &(tree->gtLsraInfo);
GenTree* op1 = tree->gtGetOp1();
GenTree* op1 = tree->gtGetOp1();
assert(info->dstCount == 0);
if (tree->TypeGet() == TYP_LONG)
{
assert((op1->OperGet() == GT_LONG) && op1->isContained());
GenTree* loVal = op1->gtGetOp1();
GenTree* hiVal = op1->gtGetOp2();
info->srcCount = 2;
loVal->gtLsraInfo.setSrcCandidates(this, RBM_LNGRET_LO);
hiVal->gtLsraInfo.setSrcCandidates(this, RBM_LNGRET_HI);
GenTree* loVal = op1->gtGetOp1();
GenTree* hiVal = op1->gtGetOp2();
info->srcCount = 2;
LocationInfoListNode* loValInfo = getLocationInfo(loVal);
LocationInfoListNode* hiValInfo = getLocationInfo(hiVal);
loValInfo->info.setSrcCandidates(this, RBM_LNGRET_LO);
hiValInfo->info.setSrcCandidates(this, RBM_LNGRET_HI);
useList.Append(loValInfo);
useList.Append(hiValInfo);
}
else
else if ((tree->TypeGet() != TYP_VOID) && !op1->isContained())
{
regMaskTP useCandidates = RBM_NONE;
......@@ -95,17 +98,17 @@ void LinearScan::TreeNodeInfoInitReturn(GenTree* tree)
}
}
LocationInfoListNode* locationInfo = getLocationInfo(op1);
if (useCandidates != RBM_NONE)
{
tree->gtOp.gtOp1->gtLsraInfo.setSrcCandidates(this, useCandidates);
locationInfo->info.setSrcCandidates(this, useCandidates);
}
useList.Append(locationInfo);
}
}
void LinearScan::TreeNodeInfoInitLclHeap(GenTree* tree)
void LinearScan::TreeNodeInfoInitLclHeap(GenTree* tree, TreeNodeInfo* info)
{
TreeNodeInfo* info = &(tree->gtLsraInfo);
assert(info->dstCount == 1);
// Need a variable number of temp regs (see genLclHeap() in codegenarm.cpp):
......@@ -175,6 +178,7 @@ void LinearScan::TreeNodeInfoInitLclHeap(GenTree* tree)
// target (regCnt) + tmp + [psp]
info->srcCount = 1;
info->internalIntCount = hasPspSym ? 2 : 1;
appendLocationInfoToList(size);
}
// If we are needed in temporary registers we should be sure that
......@@ -201,11 +205,10 @@ void LinearScan::TreeNodeInfoInitLclHeap(GenTree* tree)
// requirements needed by LSRA to build the Interval Table (source,
// destination and internal [temp] register counts).
//
void LinearScan::TreeNodeInfoInit(GenTree* tree)
void LinearScan::TreeNodeInfoInit(GenTree* tree, TreeNodeInfo* info)
{
unsigned kind = tree->OperKind();
TreeNodeInfo* info = &(tree->gtLsraInfo);
RegisterType registerType = TypeGet(tree);
unsigned kind = tree->OperKind();
RegisterType registerType = TypeGet(tree);
if (tree->isContained())
{
......@@ -235,7 +238,7 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
case GT_STORE_LCL_FLD:
case GT_STORE_LCL_VAR:
TreeNodeInfoInitStoreLoc(tree->AsLclVarCommon());
TreeNodeInfoInitStoreLoc(tree->AsLclVarCommon(), info);
break;
case GT_NOP:
......@@ -260,6 +263,7 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
op1 = tree->gtOp.gtOp1;
assert(varTypeIsFloating(op1));
assert(op1->TypeGet() == tree->TypeGet());
appendLocationInfoToList(op1);
switch (tree->gtIntrinsic.gtIntrinsicId)
{
......@@ -277,7 +281,6 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
case GT_CAST:
{
info->srcCount = 1;
assert(info->dstCount == 1);
// Non-overflow casts to/from float/double are done using SSE2 instructions
......@@ -287,6 +290,7 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
var_types castToType = tree->CastToType();
GenTreePtr castOp = tree->gtCast.CastOp();
var_types castOpType = castOp->TypeGet();
info->srcCount = GetOperandInfo(castOp);
if (tree->gtFlags & GTF_UNSIGNED)
{
castOpType = genUnsignedType(castOpType);
......@@ -371,8 +375,9 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
break;
case GT_SWITCH_TABLE:
info->srcCount = 2;
assert(info->dstCount == 0);
info->srcCount = appendBinaryLocationInfoToList(tree->AsOp());
assert(info->srcCount == 2);
break;
case GT_ASG:
......@@ -395,9 +400,9 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
// everything is made explicit by adding casts.
assert(tree->gtOp.gtOp1->TypeGet() == tree->gtOp.gtOp2->TypeGet());
info->srcCount = 2;
assert(info->dstCount == 1);
info->srcCount = appendBinaryLocationInfoToList(tree->AsOp());
assert(info->srcCount == 2);
break;
}
......@@ -406,8 +411,9 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
case GT_AND:
case GT_OR:
case GT_XOR:
info->srcCount = tree->gtOp.gtOp2->isContained() ? 1 : 2;
assert(info->dstCount == 1);
info->srcCount = appendBinaryLocationInfoToList(tree->AsOp());
assert(info->srcCount == (tree->gtOp.gtOp2->isContained() ? 1 : 2));
break;
case GT_RETURNTRAP:
......@@ -415,6 +421,7 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
// + a conditional call
info->srcCount = 1;
assert(info->dstCount == 0);
appendLocationInfoToList(tree->gtOp.gtOp1);
break;
case GT_MUL:
......@@ -430,14 +437,16 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
case GT_MULHI:
case GT_UDIV:
{
info->srcCount = 2;
assert(info->dstCount == 1);
info->srcCount = appendBinaryLocationInfoToList(tree->AsOp());
assert(info->srcCount == 2);
}
break;
case GT_MUL_LONG:
info->srcCount = 2;
info->dstCount = 2;
info->srcCount = appendBinaryLocationInfoToList(tree->AsOp());
assert(info->srcCount == 2);
break;
case GT_LIST:
......@@ -457,9 +466,11 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
tree->ClearUnusedValue();
info->isLocalDefUse = false;
// An unused GT_LONG node needs to consume its sources.
// An unused GT_LONG node needs to consume its sources, but need not produce a register.
info->srcCount = 2;
info->dstCount = 0;
appendLocationInfoToList(tree->gtGetOp1());
appendLocationInfoToList(tree->gtGetOp2());
break;
case GT_CNS_DBL:
......@@ -481,7 +492,7 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
break;
case GT_RETURN:
TreeNodeInfoInitReturn(tree);
TreeNodeInfoInitReturn(tree, info);
break;
case GT_RETFILT:
......@@ -496,7 +507,9 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
info->srcCount = 1;
info->setSrcCandidates(this, RBM_INTRET);
tree->gtOp.gtOp1->gtLsraInfo.setSrcCandidates(this, RBM_INTRET);
LocationInfoListNode* locationInfo = getLocationInfo(tree->gtOp.gtOp1);
locationInfo->info.setSrcCandidates(this, RBM_INTRET);
useList.Append(locationInfo);
}
break;
......@@ -508,6 +521,8 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
// Consumes arrLen & index - has no result
info->srcCount = 2;
assert(info->dstCount == 0);
appendLocationInfoToList(tree->AsBoundsChk()->gtIndex);
appendLocationInfoToList(tree->AsBoundsChk()->gtArrLen);
}
break;
......@@ -519,6 +534,7 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
break;
case GT_ARR_INDEX:
{
info->srcCount = 2;
assert(info->dstCount == 1);
info->internalIntCount = 1;
......@@ -526,11 +542,16 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
// For GT_ARR_INDEX, the lifetime of the arrObj must be extended because it is actually used multiple
// times while the result is being computed.
tree->AsArrIndex()->ArrObj()->gtLsraInfo.isDelayFree = true;
info->hasDelayFreeSrc = true;
break;
LocationInfoListNode* arrObjInfo = getLocationInfo(tree->AsArrIndex()->ArrObj());
arrObjInfo->info.isDelayFree = true;
useList.Append(arrObjInfo);
useList.Append(getLocationInfo(tree->AsArrIndex()->IndexExpr()));
info->hasDelayFreeSrc = true;
}
break;
case GT_ARR_OFFSET:
// This consumes the offset, if any, the arrObj and the effective index,
// and produces the flattened offset for this dimension.
assert(info->dstCount == 1);
......@@ -545,7 +566,10 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
// from any of the operand's registers, but may be the same as targetReg.
info->internalIntCount = 1;
info->srcCount = 3;
appendLocationInfoToList(tree->AsArrOffs()->gtOffset);
}
appendLocationInfoToList(tree->AsArrOffs()->gtIndex);
appendLocationInfoToList(tree->AsArrOffs()->gtArrObj);
break;
case GT_LEA:
......@@ -555,15 +579,17 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
// This LEA is instantiating an address, so we set up the srcCount and dstCount here.
info->srcCount = 0;
assert(info->dstCount == 1);
if (lea->HasBase())
{
info->srcCount++;
appendLocationInfoToList(tree->AsAddrMode()->Base());
}
if (lea->HasIndex())
{
info->srcCount++;
appendLocationInfoToList(tree->AsAddrMode()->Index());
}
assert(info->dstCount == 1);
// An internal register may be needed too; the logic here should be in sync with the
// genLeaInstruction()'s requirements for a such register.
......@@ -589,11 +615,13 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
case GT_NEG:
info->srcCount = 1;
assert(info->dstCount == 1);
appendLocationInfoToList(tree->gtOp.gtOp1);
break;
case GT_NOT:
info->srcCount = 1;
assert(info->dstCount == 1);
appendLocationInfoToList(tree->gtOp.gtOp1);
break;
case GT_LSH:
......@@ -602,7 +630,7 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
case GT_ROR:
case GT_LSH_HI:
case GT_RSH_LO:
TreeNodeInfoInitShiftRotate(tree);
TreeNodeInfoInitShiftRotate(tree, info);
break;
case GT_EQ:
......@@ -612,17 +640,18 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
case GT_GE:
case GT_GT:
case GT_CMP:
TreeNodeInfoInitCmp(tree);
TreeNodeInfoInitCmp(tree, info);
break;
case GT_CKFINITE:
info->srcCount = 1;
assert(info->dstCount == 1);
info->internalIntCount = 1;
appendLocationInfoToList(tree->gtOp.gtOp1);
break;
case GT_CALL:
TreeNodeInfoInitCall(tree->AsCall());
TreeNodeInfoInitCall(tree->AsCall(), info);
break;
case GT_ADDR:
......@@ -639,7 +668,7 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
case GT_STORE_BLK:
case GT_STORE_OBJ:
case GT_STORE_DYN_BLK:
TreeNodeInfoInitBlockStore(tree->AsBlk());
TreeNodeInfoInitBlockStore(tree->AsBlk(), info);
break;
case GT_INIT_VAL:
......@@ -648,7 +677,7 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
break;
case GT_LCLHEAP:
TreeNodeInfoInitLclHeap(tree);
TreeNodeInfoInitLclHeap(tree, info);
break;
case GT_STOREIND:
......@@ -659,14 +688,15 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
if (compiler->codeGen->gcInfo.gcIsWriteBarrierAsgNode(tree))
{
info->srcCount = 2;
TreeNodeInfoInitGCWriteBarrier(tree);
TreeNodeInfoInitGCWriteBarrier(tree, info);
break;
}
TreeNodeInfoInitIndir(tree->AsIndir());
TreeNodeInfoInitIndir(tree->AsIndir(), info);
// No contained source on ARM.
assert(!src->isContained());
info->srcCount++;
appendLocationInfoToList(src);
}
break;
......@@ -676,12 +706,13 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
assert(!tree->gtGetOp1()->isContained());
info->srcCount = 1;
info->internalIntCount = 1;
appendLocationInfoToList(tree->gtOp.gtOp1);
break;
case GT_IND:
assert(info->dstCount == 1);
info->srcCount = 1;
TreeNodeInfoInitIndir(tree->AsIndir());
TreeNodeInfoInitIndir(tree->AsIndir(), info);
break;
case GT_CATCH_ARG:
......@@ -716,24 +747,28 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
{
assert(info->dstCount == 1);
}
appendLocationInfoToList(tree->gtOp.gtOp1);
break;
case GT_PUTARG_SPLIT:
TreeNodeInfoInitPutArgSplit(tree->AsPutArgSplit());
TreeNodeInfoInitPutArgSplit(tree->AsPutArgSplit(), info);
break;
case GT_PUTARG_STK:
TreeNodeInfoInitPutArgStk(tree->AsPutArgStk());
TreeNodeInfoInitPutArgStk(tree->AsPutArgStk(), info);
break;
case GT_PUTARG_REG:
TreeNodeInfoInitPutArgReg(tree->AsUnOp());
TreeNodeInfoInitPutArgReg(tree->AsUnOp(), info);
break;
case GT_BITCAST:
{
info->srcCount = 1;
assert(info->dstCount == 1);
LocationInfoListNode* locationInfo = getLocationInfo(tree->gtOp.gtOp1);
locationInfo->info.isTgtPref = true;
useList.Append(locationInfo);
regNumber argReg = tree->gtRegNum;
regMaskTP argMask = genRegMask(argReg);
......@@ -748,7 +783,6 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
info->setDstCandidates(this, argMask);
info->setSrcCandidates(this, argMask);
tree->AsUnOp()->gtOp1->gtLsraInfo.isTgtPref = true;
}
break;
......@@ -782,14 +816,7 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
}
else if (kind & (GTK_SMPOP))
{
if (tree->gtGetOp2IfPresent() != nullptr)
{
info->srcCount = 2;
}
else
{
info->srcCount = 1;
}
info->srcCount = appendBinaryLocationInfoToList(tree->AsOp());
}
else
{
......@@ -798,9 +825,10 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
break;
case GT_INDEX_ADDR:
info->srcCount = 2;
info->dstCount = 1;
info->internalIntCount = 1;
info->srcCount = appendBinaryLocationInfoToList(tree->AsOp());
assert(info->srcCount == 2);
break;
} // end switch (tree->OperGet())
......@@ -812,6 +840,7 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
assert((info->dstCount < 2) || tree->IsMultiRegNode());
assert(info->isLocalDefUse == (tree->IsValue() && tree->IsUnusedValue()));
assert(!tree->IsUnusedValue() || (info->dstCount != 0));
assert(info->dstCount == tree->GetRegisterDstCount());
}
#endif // _TARGET_ARM_
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -15,7 +15,6 @@ class TreeNodeInfo
public:
TreeNodeInfo()
{
loc = 0;
_dstCount = 0;
_srcCount = 0;
_internalIntCount = 0;
......@@ -25,12 +24,9 @@ public:
dstCandsIndex = 0;
internalCandsIndex = 0;
isLocalDefUse = false;
isLsraAdded = false;
isDelayFree = false;
hasDelayFreeSrc = false;
isTgtPref = false;
regOptional = false;
definesAnyRegisters = false;
isInternalRegDelayFree = false;
#ifdef DEBUG
isInitialized = false;
......@@ -97,8 +93,6 @@ public:
void setInternalCandidates(LinearScan* lsra, regMaskTP mask);
void addInternalCandidates(LinearScan* lsra, regMaskTP mask);
LsraLocation loc;
public:
unsigned char srcCandsIndex;
unsigned char dstCandsIndex;
......@@ -116,9 +110,6 @@ public:
// nodes, or top-level nodes that are non-void.
unsigned char isLocalDefUse : 1;
// Is this node added by LSRA, e.g. as a resolution or copy/reload move.
unsigned char isLsraAdded : 1;
// isDelayFree is set when the register defined by this node will interfere with the destination
// of the consuming node, and therefore it must not be freed immediately after use.
unsigned char isDelayFree : 1;
......@@ -132,14 +123,6 @@ public:
// in the same register as op1.
unsigned char isTgtPref : 1;
// Whether a spilled second src can be treated as a contained operand
unsigned char regOptional : 1;
// Whether or not a node defines any registers, whether directly (for nodes where dstCout is non-zero)
// or indirectly (for contained nodes, which propagate the transitive closure of the registers
// defined by their inputs). Used during buildRefPositionsForNode in order to avoid unnecessary work.
unsigned char definesAnyRegisters : 1;
// Whether internal register needs to be different from targetReg
// in which result is produced.
unsigned char isInternalRegDelayFree : 1;
......@@ -151,7 +134,7 @@ public:
public:
// Initializes the TreeNodeInfo value with the given values.
void Initialize(LinearScan* lsra, GenTree* node, LsraLocation location);
void Initialize(LinearScan* lsra, GenTree* node);
#ifdef DEBUG
void dump(LinearScan* lsra);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册