Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 2 additions & 23 deletions src/coreclr/jit/assertionprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3835,37 +3835,16 @@ GenTree* Compiler::optAssertionProp_LclFld(ASSERT_VALARG_TP assertions, GenTreeL
break;
}

// See if the variable is equal to another variable or a constant.
// See if the variable is equal to another variable.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strange, I thought I had already removed this.

Also fgMorphTree already iterates, assuming there are opportunities to chain assertions.

//
AssertionDsc* const curAssertion = optGetAssertion(assertionIndex);
if (!curAssertion->CanPropLclVar())
{
continue;
}

// Copy prop
//
if (curAssertion->op2.kind == O2K_LCLVAR_COPY)
if (curAssertion->CanPropLclVar() && (curAssertion->op2.kind == O2K_LCLVAR_COPY))
{
GenTree* const newTree = optCopyAssertionProp(curAssertion, tree, stmt DEBUGARG(assertionIndex));
if (newTree != nullptr)
{
return newTree;
}

continue;
}

// Constant prop
//
if (curAssertion->op1.lcl.lclNum == tree->GetLclNum())
{
GenTree* const newTree = optConstantAssertionProp(curAssertion, tree, stmt DEBUGARG(assertionIndex));

if (newTree != nullptr)
{
return newTree;
}
}
}

Expand Down
3 changes: 0 additions & 3 deletions src/coreclr/jit/codegenarm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1009,9 +1009,6 @@ void CodeGen::genCodeForStoreLclFld(GenTreeLclFld* tree)
unsigned varNum = tree->GetLclNum();
LclVarDsc* varDsc = compiler->lvaGetDesc(varNum);

// Ensure that lclVar nodes are typed correctly.
assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));

GenTree* data = tree->gtOp1;
regNumber dataReg = REG_NA;
genConsumeRegs(data);
Expand Down
3 changes: 0 additions & 3 deletions src/coreclr/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2685,9 +2685,6 @@ void CodeGen::genCodeForStoreLclFld(GenTreeLclFld* tree)
unsigned varNum = tree->GetLclNum();
LclVarDsc* varDsc = compiler->lvaGetDesc(varNum);

// Ensure that lclVar nodes are typed correctly.
assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));

GenTree* data = tree->gtOp1;
genConsumeRegs(data);

Expand Down
4 changes: 0 additions & 4 deletions src/coreclr/jit/fgdiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3032,10 +3032,6 @@ void Compiler::fgDebugCheckFlags(GenTree* tree)
expectedFlags |= (GTF_GLOB_REF | GTF_ASG);
break;

case GT_LCL_VAR:
assert((tree->gtFlags & GTF_VAR_FOLDED_IND) == 0);
break;

case GT_QMARK:
assert(!op1->CanCSE());
assert(op1->OperIsCompare() || op1->IsIntegralConst(0) || op1->IsIntegralConst(1));
Expand Down
5 changes: 0 additions & 5 deletions src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -472,11 +472,6 @@ enum GenTreeFlags : unsigned int
GTF_VAR_ITERATOR = 0x01000000, // GT_LCL_VAR -- this is a iterator reference in the loop condition
GTF_VAR_CLONED = 0x00800000, // GT_LCL_VAR -- this node has been cloned or is a clone
GTF_VAR_CONTEXT = 0x00400000, // GT_LCL_VAR -- this node is part of a runtime lookup
GTF_VAR_FOLDED_IND = 0x00200000, // GT_LCL_VAR -- this node was folded from *(typ*)&lclVar expression tree in fgMorphSmpOp()
// where 'typ' is a small type and 'lclVar' corresponds to a normalized-on-store local variable.
// This flag identifies such nodes in order to make sure that fgDoNormalizeOnStore() is called
// on their parents in post-order morph.
// Relevant for inlining optimizations (see fgInlinePrependStatements)

// For additional flags for GT_CALL node see GTF_CALL_M_*

Expand Down
110 changes: 84 additions & 26 deletions src/coreclr/jit/lclmorph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
{
None,
Nop,
BitCast,
LclVar,
LclFld
};
Expand Down Expand Up @@ -702,7 +703,6 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
if (node->OperIs(GT_LCL_VAR, GT_LCL_FLD))
{
// If the location is accessed directly then we don't need to do anything.

assert(node->AsLclVarCommon()->GetLclNum() == val.LclNum());
}
else
Expand Down Expand Up @@ -899,9 +899,12 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
{
assert(val.IsLocation());

ClassLayout* indirLayout = nullptr;
IndirTransform transform = SelectLocalIndirTransform(val, user, &indirLayout);
GenTree* indir = val.Node();
ClassLayout* indirLayout = nullptr;
IndirTransform transform = SelectLocalIndirTransform(val, user, &indirLayout);
GenTree* indir = val.Node();
unsigned lclNum = val.LclNum();
LclVarDsc* varDsc = m_compiler->lvaGetDesc(lclNum);
GenTreeLclVarCommon* lclNode = nullptr;

switch (transform)
{
Expand All @@ -914,39 +917,56 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
m_stmtModified = true;
return;

case IndirTransform::BitCast:
indir->ChangeOper(GT_BITCAST);
indir->gtGetOp1()->ChangeOper(GT_LCL_VAR);
indir->gtGetOp1()->ChangeType(varDsc->TypeGet());
indir->gtGetOp1()->AsLclVar()->SetLclNum(lclNum);
lclNode = indir->gtGetOp1()->AsLclVarCommon();
break;

case IndirTransform::LclVar:
if (indir->TypeGet() != varDsc->TypeGet())
{
assert(genTypeSize(indir) == genTypeSize(varDsc)); // BOOL <-> UBYTE.
indir->ChangeType(varDsc->lvNormalizeOnLoad() ? varDsc->TypeGet() : genActualType(varDsc));
}
indir->ChangeOper(GT_LCL_VAR);
indir->AsLclVar()->SetLclNum(val.LclNum());
indir->AsLclVar()->SetLclNum(lclNum);
lclNode = indir->AsLclVarCommon();
break;

case IndirTransform::LclFld:
indir->ChangeOper(GT_LCL_FLD);
indir->AsLclFld()->SetLclNum(val.LclNum());
indir->AsLclFld()->SetLclNum(lclNum);
indir->AsLclFld()->SetLclOffs(val.Offset());
indir->AsLclFld()->SetLayout(indirLayout);
lclNode = indir->AsLclVarCommon();

// Promoted locals aren't currently handled here so partial access can't be
// later be transformed into a LCL_VAR and the variable cannot be enregistered.
m_compiler->lvaSetVarDoNotEnregister(val.LclNum() DEBUGARG(DoNotEnregisterReason::LocalField));
m_compiler->lvaSetVarDoNotEnregister(lclNum DEBUGARG(DoNotEnregisterReason::LocalField));
break;

default:
unreached();
}

GenTreeLclVarCommon* lclNode = indir->AsLclVarCommon();
GenTreeFlags lclNodeFlags = GTF_EMPTY;
GenTreeFlags lclNodeFlags = GTF_EMPTY;

if (user->OperIs(GT_ASG) && (user->AsOp()->gtGetOp1() == lclNode))
if (user->OperIs(GT_ASG) && (user->AsOp()->gtGetOp1() == indir))
{
lclNodeFlags |= (GTF_VAR_DEF | GTF_DONT_CSE);

unsigned lhsSize = lclNode->TypeIs(TYP_STRUCT) ? indirLayout->GetSize() : genTypeSize(lclNode);
unsigned lclSize = m_compiler->lvaLclExactSize(val.LclNum());
if (lhsSize != lclSize)
if (!indir->OperIs(GT_LCL_VAR))
{
assert(lhsSize < lclSize);
lclNodeFlags |= GTF_VAR_USEASG;
unsigned lhsSize = indir->TypeIs(TYP_STRUCT) ? indirLayout->GetSize() : genTypeSize(indir);
unsigned lclSize = m_compiler->lvaLclExactSize(lclNum);
if (lhsSize != lclSize)
{
assert(lhsSize < lclSize);
lclNodeFlags |= GTF_VAR_USEASG;
}
}
}

Expand Down Expand Up @@ -981,19 +1001,14 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>

LclVarDsc* varDsc = m_compiler->lvaGetDesc(val.LclNum());

if (varDsc->TypeGet() != TYP_STRUCT)
if (varTypeIsSIMD(varDsc))
{
// TODO-ADDR: Skip integral/floating point variables for now, they're more
// complicated to transform. We can always turn an indirect access of such
// a variable into a LCL_FLD but that blocks enregistration so we need to
// detect those case where we can use LCL_VAR instead, perhaps in conjunction
// with CAST and/or BITCAST.
// Also skip SIMD variables for now, fgMorphFieldAssignToSimdSetElement and
// TODO-ADDR: skip SIMD variables for now, fgMorphFieldAssignToSimdSetElement and
// others need to be updated to recognize LCL_FLDs.
return IndirTransform::None;
}

if (!indir->TypeIs(TYP_STRUCT))
if (indir->TypeGet() != TYP_STRUCT)
{
if (varDsc->lvPromoted)
{
Expand All @@ -1002,12 +1017,55 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
return IndirTransform::None;
}

// As we are only handling non-promoted STRUCT locals right now, the only
// possible transformation for non-STRUCT indirect uses is LCL_FLD.
assert(varDsc->TypeGet() == TYP_STRUCT);
if (indir->TypeGet() == varDsc->TypeGet())
{
return IndirTransform::LclVar;
}

// Locals are not enregistered when optimizations are disabled; there is no point
// in spending time finding LCL_VAR-equivalent trees for them. TODO-ADDR: move
// this check earlier.
if (m_compiler->opts.OptimizationDisabled())
{
return IndirTransform::LclFld;
}

// Bool and ubyte are the same type.
if ((indir->TypeIs(TYP_BOOL) && (varDsc->TypeGet() == TYP_UBYTE)) ||
(indir->TypeIs(TYP_UBYTE) && (varDsc->TypeGet() == TYP_BOOL)))
{
return IndirTransform::LclVar;
}

// For small locals on the LHS we can ignore the signed/unsigned diff.
if (user->OperIs(GT_ASG) && (user->gtGetOp1() == indir) &&
(varTypeToSigned(indir) == varTypeToSigned(varDsc)))
{
assert(varTypeIsSmall(indir));
return IndirTransform::LclVar;
}

// Turn this into a bitcast if we can.
if ((genTypeSize(indir) == genTypeSize(varDsc)) && (varTypeIsFloating(indir) || varTypeIsFloating(varDsc)))
{
// TODO-ADDR: enable this optimization for all users and all targets.
if (user->OperIs(GT_RETURN) && (genTypeSize(indir) <= TARGET_POINTER_SIZE))
{
return IndirTransform::BitCast;
}
}

return IndirTransform::LclFld;
}

if (varDsc->TypeGet() != TYP_STRUCT)
{
// TODO-ADDR: STRUCT uses of primitives require more work: "fgMorphOneAsgBlockOp"
// and init block morphing need to be updated to recognize them. Alternatively,
// we could consider moving some of their functionality here.
return IndirTransform::None;
}

ClassLayout* indirLayout = nullptr;

if (indir->OperIs(GT_FIELD))
Expand Down
45 changes: 0 additions & 45 deletions src/coreclr/jit/morph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10807,13 +10807,6 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA
{
case GT_ASG:

if (op1->OperIs(GT_LCL_VAR) && ((op1->gtFlags & GTF_VAR_FOLDED_IND) != 0))
{
op1->gtFlags &= ~GTF_VAR_FOLDED_IND;
tree = fgDoNormalizeOnStore(tree);
op2 = tree->gtGetOp2();
}

lclVarTree = fgIsIndirOfAddrOfLocal(op1);
if (lclVarTree != nullptr)
{
Expand Down Expand Up @@ -11230,47 +11223,9 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA
}
}
}
// If the type of the IND (typ) is a "small int", and the type of the local has the
// same width, then we can reduce to just the local variable -- it will be
// correctly normalized.
//
// The below transformation cannot be applied if the local var needs to be normalized on load.
else if (varTypeIsSmall(typ) && (genTypeSize(varDsc) == genTypeSize(typ)) &&
!lvaTable[lclNum].lvNormalizeOnLoad())
{
const bool definitelyLoad = (tree->gtFlags & GTF_DONT_CSE) == 0;
const bool possiblyStore = !definitelyLoad;

if (possiblyStore || (varTypeIsUnsigned(varDsc) == varTypeIsUnsigned(typ)))
{
typ = temp->TypeGet();
tree->gtType = typ;
foldAndReturnTemp = true;

if (possiblyStore)
{
// This node can be on the left-hand-side of an assignment node.
// Mark this node with GTF_VAR_FOLDED_IND to make sure that fgDoNormalizeOnStore()
// is called on its parent in post-order morph.
temp->gtFlags |= GTF_VAR_FOLDED_IND;
}
}
}
// For matching types we can fold
else if (!varTypeIsStruct(typ) && (lvaTable[lclNum].lvType == typ) &&
!lvaTable[lclNum].lvNormalizeOnLoad())
{
tree->gtType = typ = temp->TypeGet();
foldAndReturnTemp = true;
}
// Otherwise will will fold this into a GT_LCL_FLD below
// where we check (temp != nullptr)
}
else // !temp->OperIsLocal()
{
// We don't try to fold away the GT_IND/GT_ADDR for this case
temp = nullptr;
}
}
else
{
Expand Down