Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 4157555

Browse files
committed
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 #7255
1 parent d6046f0 commit 4157555

File tree

15 files changed

+3530
-3308
lines changed

15 files changed

+3530
-3308
lines changed

src/jit/emitarm64.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10070,11 +10070,13 @@ void emitter::emitDispImm(ssize_t imm, bool addComma, bool alwaysHex /* =false *
1007010070
printf("#");
1007110071
}
1007210072

10073-
// Munge any pointers if we want diff-able disassembly
10073+
// Munge any pointers if we want diff-able disassembly.
10074+
// Since some may be emitted as partial words, print as diffable anything that has
10075+
// significant bits beyond the lowest 8-bits.
1007410076
if (emitComp->opts.disDiffable)
1007510077
{
10076-
ssize_t top44bits = (imm >> 20);
10077-
if ((top44bits != 0) && (top44bits != -1))
10078+
ssize_t top56bits = (imm >> 8);
10079+
if ((top56bits != 0) && (top56bits != -1))
1007810080
imm = 0xD1FFAB1E;
1007910081
}
1008010082

src/jit/gentree.cpp

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,61 @@ bool GenTree::gtHasReg() const
764764
return hasReg;
765765
}
766766

767+
//-----------------------------------------------------------------------------
768+
// GetRegisterDstCount: Get the number of registers defined by the node.
769+
//
770+
// Arguments:
771+
// None
772+
//
773+
// Return Value:
774+
// The number of registers that this node defines.
775+
//
776+
// Notes:
777+
// This should not be called on a contained node.
778+
// This does not look at the actual register assignments, if any, and so
779+
// is valid after Lowering.
780+
//
781+
int GenTree::GetRegisterDstCount() const
782+
{
783+
assert(!isContained());
784+
if (!IsMultiRegNode())
785+
{
786+
return (IsValue()) ? 1 : 0;
787+
}
788+
else if (IsMultiRegCall())
789+
{
790+
// temporarily cast away const-ness as AsCall() method is not declared const
791+
GenTree* temp = const_cast<GenTree*>(this);
792+
return temp->AsCall()->GetReturnTypeDesc()->GetReturnRegCount();
793+
}
794+
else if (IsCopyOrReloadOfMultiRegCall())
795+
{
796+
// A multi-reg copy or reload, will have valid regs for only those
797+
// positions that need to be copied or reloaded. Hence we need
798+
// to consider only those registers for computing reg mask.
799+
800+
GenTree* tree = const_cast<GenTree*>(this);
801+
GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload();
802+
GenTreeCall* call = copyOrReload->gtGetOp1()->AsCall();
803+
return call->GetReturnTypeDesc()->GetReturnRegCount();
804+
}
805+
#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
806+
else if (OperIsPutArgSplit())
807+
{
808+
return (const_cast<GenTree*>(this))->AsPutArgSplit()->gtNumRegs;
809+
}
810+
// A PUTARG_REG could be a MultiRegOp on ARM since we could move a double register to two int registers,
811+
// either for all double parameters w/SoftFP or for varargs).
812+
else
813+
{
814+
assert(OperIsMultiRegOp());
815+
return (TypeGet() == TYP_LONG) ? 2 : 1;
816+
}
817+
#endif // !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
818+
assert(!"Unexpected multi-reg node");
819+
return 0;
820+
}
821+
767822
//---------------------------------------------------------------
768823
// gtGetRegMask: Get the reg mask of the node.
769824
//
@@ -16065,19 +16120,6 @@ bool Compiler::gtComplexityExceeds(GenTreePtr* tree, unsigned limit)
1606516120
}
1606616121
}
1606716122

16068-
// -------------------------------------------------------------------------
16069-
// IsRegOptional: Returns true if this gentree node is marked by lowering to
16070-
// indicate that codegen can still generate code even if it wasn't allocated
16071-
// a register.
16072-
bool GenTree::IsRegOptional() const
16073-
{
16074-
#ifdef LEGACY_BACKEND
16075-
return false;
16076-
#else
16077-
return gtLsraInfo.regOptional;
16078-
#endif
16079-
}
16080-
1608116123
bool GenTree::IsPhiNode()
1608216124
{
1608316125
return (OperGet() == GT_PHI_ARG) || (OperGet() == GT_PHI) || IsPhiDefn();

src/jit/gentree.h

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,8 @@ struct GenTree
680680
void CopyReg(GenTreePtr from);
681681
bool gtHasReg() const;
682682

683+
int GetRegisterDstCount() const;
684+
683685
regMaskTP gtGetRegMask() const;
684686

685687
unsigned gtFlags; // see GTF_xxxx below
@@ -702,10 +704,6 @@ struct GenTree
702704
regMaskSmall gtUsedRegs; // set of used (trashed) registers
703705
#endif // LEGACY_BACKEND
704706

705-
#ifndef LEGACY_BACKEND
706-
TreeNodeInfo gtLsraInfo;
707-
#endif // !LEGACY_BACKEND
708-
709707
void SetVNsFromNode(GenTreePtr tree)
710708
{
711709
gtVNPair = tree->gtVNPair;
@@ -1022,8 +1020,9 @@ struct GenTree
10221020
#define GTF_DEBUG_NODE_LARGE 0x00000004
10231021
#define GTF_DEBUG_NODE_CG_PRODUCED 0x00000008 // genProduceReg has been called on this node
10241022
#define GTF_DEBUG_NODE_CG_CONSUMED 0x00000010 // genConsumeReg has been called on this node
1023+
#define GTF_DEBUG_NODE_LSRA_ADDED 0x00000020 // This node was added by LSRA
10251024

1026-
#define GTF_DEBUG_NODE_MASK 0x0000001F // These flags are all node (rather than operation) properties.
1025+
#define GTF_DEBUG_NODE_MASK 0x0000003F // These flags are all node (rather than operation) properties.
10271026

10281027
#define GTF_DEBUG_VAR_CSE_REF 0x00800000 // GT_LCL_VAR -- This is a CSE LCL_VAR node
10291028
#endif // defined(DEBUG)
@@ -1133,10 +1132,20 @@ struct GenTree
11331132
}
11341133
}
11351134

1136-
// NOTE: the three UnusedValue helpers immediately below are defined in lir.h.
1135+
// LIR flags
1136+
// These helper methods, along with the flag values they manipulate, are defined in lir.h
1137+
//
1138+
// UnusedValue indicates that, although this node produces a value, it is unused.
11371139
inline void SetUnusedValue();
11381140
inline void ClearUnusedValue();
11391141
inline bool IsUnusedValue() const;
1142+
// RegOptional indicates that codegen can still generate code even if it isn't allocated a register.
1143+
inline bool IsRegOptional() const;
1144+
inline void SetRegOptional();
1145+
inline void ClearRegOptional();
1146+
#ifdef DEBUG
1147+
void dumpLIRFlags();
1148+
#endif
11401149

11411150
bool OperIs(genTreeOps oper) const
11421151
{
@@ -2135,17 +2144,6 @@ struct GenTree
21352144
inline var_types CastFromType();
21362145
inline var_types& CastToType();
21372146

2138-
// Returns true if this gentree node is marked by lowering to indicate
2139-
// that codegen can still generate code even if it wasn't allocated a
2140-
// register.
2141-
bool IsRegOptional() const;
2142-
#ifndef LEGACY_BACKEND
2143-
void ClearRegOptional()
2144-
{
2145-
gtLsraInfo.regOptional = false;
2146-
}
2147-
#endif
2148-
21492147
// Returns "true" iff "this" is a phi-related node (i.e. a GT_PHI_ARG, GT_PHI, or a PhiDefn).
21502148
bool IsPhiNode();
21512149

src/jit/lir.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1763,3 +1763,10 @@ void LIR::InsertBeforeTerminator(BasicBlock* block, LIR::Range&& range)
17631763

17641764
blockRange.InsertBefore(insertionPoint, std::move(range));
17651765
}
1766+
1767+
#ifdef DEBUG
1768+
void GenTree::dumpLIRFlags()
1769+
{
1770+
JITDUMP("[%c%c%c]", IsUnusedValue() ? 'U' : '-', IsRegOptional() ? 'O' : '-');
1771+
}
1772+
#endif

src/jit/lir.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ class LIR final
3838
// that this bit should not be assumed to be valid
3939
// at all points during compilation: it is currently
4040
// only computed during target-dependent lowering.
41+
42+
RegOptional = 0x04, // Set on a node if it produces a value, but does not
43+
// require a register (i.e. it can be used from memory).
4144
};
4245
};
4346

@@ -327,4 +330,19 @@ inline bool GenTree::IsUnusedValue() const
327330
return (gtLIRFlags & LIR::Flags::UnusedValue) != 0;
328331
}
329332

333+
inline void GenTree::SetRegOptional()
334+
{
335+
gtLIRFlags |= LIR::Flags::RegOptional;
336+
}
337+
338+
inline void GenTree::ClearRegOptional()
339+
{
340+
gtLIRFlags &= ~LIR::Flags::RegOptional;
341+
}
342+
343+
inline bool GenTree::IsRegOptional() const
344+
{
345+
return (gtLIRFlags & LIR::Flags::RegOptional) != 0;
346+
}
347+
330348
#endif // _LIR_H_

src/jit/lower.cpp

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4747,19 +4747,19 @@ bool Lowering::LowerUnsignedDivOrMod(GenTreeOp* divMod)
47474747
// node - pointer to the DIV or MOD node
47484748
//
47494749
// Returns:
4750-
// The next node to lower.
4750+
// nullptr if no transformation is done, or the next node in the transformed node sequence that
4751+
// needs to be lowered.
47514752
//
47524753
GenTree* Lowering::LowerConstIntDivOrMod(GenTree* node)
47534754
{
47544755
assert((node->OperGet() == GT_DIV) || (node->OperGet() == GT_MOD));
4755-
GenTree* next = node->gtNext;
47564756
GenTree* divMod = node;
47574757
GenTree* dividend = divMod->gtGetOp1();
47584758
GenTree* divisor = divMod->gtGetOp2();
47594759

47604760
if (!divisor->IsCnsIntOrI())
47614761
{
4762-
return next; // no transformations to make
4762+
return nullptr; // no transformations to make
47634763
}
47644764

47654765
const var_types type = divMod->TypeGet();
@@ -4770,7 +4770,7 @@ GenTree* Lowering::LowerConstIntDivOrMod(GenTree* node)
47704770
// We shouldn't see a divmod with constant operands here but if we do then it's likely
47714771
// because optimizations are disabled or it's a case that's supposed to throw an exception.
47724772
// Don't optimize this.
4773-
return next;
4773+
return nullptr;
47744774
}
47754775

47764776
ssize_t divisorValue = divisor->gtIntCon.IconValue();
@@ -4786,7 +4786,7 @@ GenTree* Lowering::LowerConstIntDivOrMod(GenTree* node)
47864786
// case so optimizing this case would break C# code.
47874787

47884788
// A runtime check could be used to handle this case but it's probably too rare to matter.
4789-
return next;
4789+
return nullptr;
47904790
}
47914791

47924792
bool isDiv = divMod->OperGet() == GT_DIV;
@@ -4798,8 +4798,7 @@ GenTree* Lowering::LowerConstIntDivOrMod(GenTree* node)
47984798
// If the divisor is the minimum representable integer value then we can use a compare,
47994799
// the result is 1 iff the dividend equals divisor.
48004800
divMod->SetOper(GT_EQ);
4801-
ContainCheckCompare(divMod->AsOp());
4802-
return next;
4801+
return node;
48034802
}
48044803
}
48054804

@@ -4810,7 +4809,7 @@ GenTree* Lowering::LowerConstIntDivOrMod(GenTree* node)
48104809
{
48114810
if (comp->opts.MinOpts())
48124811
{
4813-
return next;
4812+
return nullptr;
48144813
}
48154814

48164815
#if defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
@@ -4921,15 +4920,15 @@ GenTree* Lowering::LowerConstIntDivOrMod(GenTree* node)
49214920
return mulhi;
49224921
#else
49234922
// Currently there's no GT_MULHI for ARM32
4924-
return next;
4923+
return nullptr;
49254924
#endif
49264925
}
49274926

49284927
// We're committed to the conversion now. Go find the use if any.
49294928
LIR::Use use;
49304929
if (!BlockRange().TryGetUse(node, &use))
49314930
{
4932-
return next;
4931+
return nullptr;
49334932
}
49344933

49354934
// We need to use the dividend node multiple times so its value needs to be
@@ -5030,13 +5029,14 @@ GenTree* Lowering::LowerSignedDivOrMod(GenTreePtr node)
50305029
if (!varTypeIsFloating(node->TypeGet()))
50315030
#endif // _TARGET_XARCH_
50325031
{
5033-
next = LowerConstIntDivOrMod(node);
5034-
}
5035-
5036-
if ((node->OperGet() == GT_DIV) || (node->OperGet() == GT_MOD))
5037-
{
5038-
ContainCheckDivOrMod(node->AsOp());
5032+
// LowerConstIntDivOrMod will return nullptr if it doesn't transform the node.
5033+
GenTree* newNode = LowerConstIntDivOrMod(node);
5034+
if (newNode != nullptr)
5035+
{
5036+
return newNode;
5037+
}
50395038
}
5039+
ContainCheckDivOrMod(node->AsOp());
50405040

50415041
return next;
50425042
}
@@ -5890,7 +5890,7 @@ void Lowering::ContainCheckDivOrMod(GenTreeOp* node)
58905890
{
58915891
// If there are no containable operands, we can make an operand reg optional.
58925892
// SSE2 allows only divisor to be a memory-op.
5893-
SetRegOptional(divisor);
5893+
divisor->SetRegOptional();
58945894
}
58955895
return;
58965896
}
@@ -5912,7 +5912,7 @@ void Lowering::ContainCheckDivOrMod(GenTreeOp* node)
59125912
{
59135913
// If there are no containable operands, we can make an operand reg optional.
59145914
// Div instruction allows only divisor to be a memory op.
5915-
SetRegOptional(divisor);
5915+
divisor->SetRegOptional();
59165916
}
59175917
#endif // _TARGET_XARCH_
59185918
}

src/jit/lower.h

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -224,22 +224,6 @@ class Lowering : public Phase
224224
bool IsCallTargetInRange(void* addr);
225225

226226
#if defined(_TARGET_XARCH_)
227-
//----------------------------------------------------------------------
228-
// SetRegOptional - sets a bit to indicate to LSRA that register
229-
// for a given tree node is optional for codegen purpose. If no
230-
// register is allocated to such a tree node, its parent node treats
231-
// it as a contained memory operand during codegen.
232-
//
233-
// Arguments:
234-
// tree - GenTree node
235-
//
236-
// Returns
237-
// None
238-
void SetRegOptional(GenTree* tree)
239-
{
240-
tree->gtLsraInfo.regOptional = true;
241-
}
242-
243227
GenTree* PreferredRegOptionalOperand(GenTree* tree);
244228

245229
// ------------------------------------------------------------------
@@ -273,13 +257,18 @@ class Lowering : public Phase
273257
const bool op1Legal = tree->OperIsCommutative() && (operatorSize == genTypeSize(op1->TypeGet()));
274258
const bool op2Legal = operatorSize == genTypeSize(op2->TypeGet());
275259

260+
GenTree* regOptionalOperand = nullptr;
276261
if (op1Legal)
277262
{
278-
SetRegOptional(op2Legal ? PreferredRegOptionalOperand(tree) : op1);
263+
regOptionalOperand = op2Legal ? PreferredRegOptionalOperand(tree) : op1;
279264
}
280265
else if (op2Legal)
281266
{
282-
SetRegOptional(op2);
267+
regOptionalOperand = op2;
268+
}
269+
if (regOptionalOperand != nullptr)
270+
{
271+
regOptionalOperand->SetRegOptional();
283272
}
284273
}
285274
#endif // defined(_TARGET_XARCH_)

0 commit comments

Comments
 (0)