Skip to content

Commit 22c3a1b

Browse files
author
Sergey Andreenko
committed
Don't mark LCL_VAR that is used in RETURN(IND(ADDR(LCL_VAR)) as address taken when possible
11 methods improved, 3 regression fixed, -100 bytes diff.
1 parent b2ce59f commit 22c3a1b

File tree

3 files changed

+83
-35
lines changed

3 files changed

+83
-35
lines changed

src/coreclr/src/jit/compiler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5595,6 +5595,7 @@ class Compiler
55955595
GenTree* fgMorphCopyBlock(GenTree* tree);
55965596
GenTree* fgMorphForRegisterFP(GenTree* tree);
55975597
GenTree* fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac = nullptr);
5598+
GenTree* fgMorphRetInd(GenTreeUnOp* tree);
55985599
GenTree* fgMorphModToSubMulDiv(GenTreeOp* tree);
55995600
GenTree* fgMorphSmpOpOptional(GenTreeOp* tree);
56005601

src/coreclr/src/jit/lower.cpp

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2935,7 +2935,6 @@ void Lowering::LowerRet(GenTreeUnOp* ret)
29352935
if ((ret->TypeGet() != TYP_VOID) && !varTypeIsStruct(ret) &&
29362936
(varTypeUsesFloatReg(ret) != varTypeUsesFloatReg(ret->gtGetOp1())))
29372937
{
2938-
assert(comp->compDoOldStructRetyping());
29392938
GenTreeUnOp* bitcast = new (comp, GT_BITCAST) GenTreeOp(GT_BITCAST, ret->TypeGet(), ret->gtGetOp1(), nullptr);
29402939
ret->gtOp1 = bitcast;
29412940
BlockRange().InsertBefore(ret, bitcast);
@@ -2952,15 +2951,26 @@ void Lowering::LowerRet(GenTreeUnOp* ret)
29522951
if (varTypeIsStruct(ret->TypeGet()))
29532952
{
29542953
assert(!comp->compDoOldStructRetyping());
2955-
bool actualTypesMatch = false;
2956-
if (genActualType(comp->info.compRetNativeType) == genActualType(retVal->TypeGet()))
2954+
bool constStructInit = retVal->IsConstInitVal();
2955+
2956+
bool actualTypesMatch = false;
2957+
var_types retActualType = genActualType(comp->info.compRetNativeType);
2958+
var_types retValActualType = genActualType(retVal->TypeGet());
2959+
if (retActualType == retValActualType)
29572960
{
29582961
// This could happen if we have retyped op1 as a primitive type during struct promotion,
29592962
// check `retypedFieldsMap` for details.
29602963
actualTypesMatch = true;
29612964
}
2962-
bool constStructInit = retVal->IsConstInitVal();
2963-
assert(actualTypesMatch || constStructInit);
2965+
assert(comp->info.compRetNativeType != TYP_STRUCT);
2966+
2967+
bool implicitCastFromSameOrBiggerSize = false;
2968+
if (genTypeSize(retActualType) <= genTypeSize(retValActualType))
2969+
{
2970+
implicitCastFromSameOrBiggerSize = true;
2971+
}
2972+
2973+
assert(actualTypesMatch || constStructInit || implicitCastFromSameOrBiggerSize);
29642974
}
29652975
else
29662976
{
@@ -3248,13 +3258,6 @@ void Lowering::LowerRetStructLclVar(GenTreeUnOp* ret)
32483258
unsigned lclNum = lclVar->GetLclNum();
32493259
LclVarDsc* varDsc = comp->lvaGetDesc(lclNum);
32503260

3251-
#ifdef DEBUG
3252-
if (comp->gtGetStructHandleIfPresent(lclVar) == NO_CLASS_HANDLE)
3253-
{
3254-
// a promoted struct field was retyped as its only field.
3255-
assert(varDsc->lvIsStructField);
3256-
}
3257-
#endif
32583261
if (varDsc->lvPromoted && (comp->lvaGetPromotionType(lclNum) == Compiler::PROMOTION_TYPE_INDEPENDENT))
32593262
{
32603263
if (varDsc->lvFieldCnt == 1)

src/coreclr/src/jit/morph.cpp

Lines changed: 67 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11965,30 +11965,9 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
1196511965

1196611966
return tree;
1196711967
}
11968-
if (varTypeIsStruct(tree) && op1->OperIs(GT_OBJ, GT_BLK))
11968+
if (!compDoOldStructRetyping() && !tree->TypeIs(TYP_VOID) && op1->OperIs(GT_OBJ, GT_BLK, GT_IND))
1196911969
{
11970-
assert(!compDoOldStructRetyping());
11971-
GenTree* addr = op1->AsBlk()->Addr();
11972-
// if we return `OBJ` or `BLK` from a local var, lcl var has to have a stack address.
11973-
if (addr->OperIs(GT_ADDR) && addr->gtGetOp1()->OperIs(GT_LCL_VAR))
11974-
{
11975-
GenTreeLclVar* lclVar = addr->gtGetOp1()->AsLclVar();
11976-
assert(!gtIsActiveCSE_Candidate(addr) && !gtIsActiveCSE_Candidate(op1));
11977-
if (gtGetStructHandle(tree) == gtGetStructHandleIfPresent(lclVar))
11978-
{
11979-
// Fold *(&x).
11980-
tree->AsUnOp()->gtOp1 = op1;
11981-
DEBUG_DESTROY_NODE(op1);
11982-
DEBUG_DESTROY_NODE(addr);
11983-
op1 = lclVar;
11984-
}
11985-
else
11986-
{
11987-
// TODO-1stClassStructs: It is not address-taken or block operation,
11988-
// but the current IR doesn't allow to express that cast without stack, see #11413.
11989-
lvaSetVarDoNotEnregister(lclVar->GetLclNum() DEBUGARG(DNER_BlockOp));
11990-
}
11991-
}
11970+
op1 = fgMorphRetInd(tree->AsUnOp());
1199211971
}
1199311972
break;
1199411973

@@ -14209,6 +14188,71 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
1420914188

1421014189
return tree;
1421114190
}
14191+
14192+
//----------------------------------------------------------------------------------------------
14193+
// fgMorphRetInd: Try to get rid of extra IND(ADDR()) pairs in a return tree.
14194+
//
14195+
// Arguments:
14196+
// node - The return node that uses an indirection.
14197+
//
14198+
// Return Value:
14199+
// the original op1 of the ret if there was no optimization or an optimized new op1.
14200+
//
14201+
GenTree* Compiler::fgMorphRetInd(GenTreeUnOp* ret)
14202+
{
14203+
assert(!compDoOldStructRetyping());
14204+
assert(ret->OperIs(GT_RETURN));
14205+
assert(ret->gtGetOp1()->OperIs(GT_IND, GT_BLK, GT_OBJ));
14206+
GenTreeIndir* ind = ret->gtGetOp1()->AsIndir();
14207+
GenTree* addr = ind->Addr();
14208+
14209+
if (addr->OperIs(GT_ADDR) && addr->gtGetOp1()->OperIs(GT_LCL_VAR))
14210+
{
14211+
// If `return` retypes LCL_VAR as a smaller struct it should not set `doNotEnregister` on that
14212+
// LclVar.
14213+
// Example: in `Vector128:AsVector2` we have RETURN SIMD8(OBJ SIMD8(ADDR byref(LCL_VAR SIMD16))).
14214+
GenTreeLclVar* lclVar = addr->gtGetOp1()->AsLclVar();
14215+
if (!lvaIsImplicitByRefLocal(lclVar->GetLclNum()))
14216+
{
14217+
assert(!gtIsActiveCSE_Candidate(addr) && !gtIsActiveCSE_Candidate(ind));
14218+
unsigned indSize;
14219+
if (ind->OperIs(GT_IND))
14220+
{
14221+
indSize = genTypeSize(ind);
14222+
}
14223+
else
14224+
{
14225+
indSize = ind->AsBlk()->GetLayout()->GetSize();
14226+
}
14227+
14228+
LclVarDsc* varDsc = lvaGetDesc(lclVar);
14229+
14230+
unsigned lclVarSize;
14231+
if (!lclVar->TypeIs(TYP_STRUCT))
14232+
14233+
{
14234+
lclVarSize = genTypeSize(lclVar->TypeGet());
14235+
}
14236+
else
14237+
{
14238+
lclVarSize = varDsc->lvExactSize;
14239+
}
14240+
assert((indSize <= lclVarSize) || varDsc->lvDoNotEnregister);
14241+
if (indSize <= lclVarSize)
14242+
{
14243+
// Fold (TYPE1)*(&(TYPE2)x) even if types do not match, lowering will handle it.
14244+
// Getting rid of this IND(ADDR()) pair allows to keep lclVar as not address taken
14245+
// and enregister it.
14246+
DEBUG_DESTROY_NODE(ind);
14247+
DEBUG_DESTROY_NODE(addr);
14248+
ret->gtOp1 = lclVar;
14249+
return ret->gtOp1;
14250+
}
14251+
}
14252+
}
14253+
return ind;
14254+
}
14255+
1421214256
#ifdef _PREFAST_
1421314257
#pragma warning(pop)
1421414258
#endif

0 commit comments

Comments
 (0)