Skip to content

Commit 3dc3eba

Browse files
Enable TYP_STRUCT LCL_VAR/LCL_FLD call args on Windows x64 (#70777)
* Fix forward sub * Enable folding in local morph * Morph: TYP_STRUCT LCL_FLD
1 parent 222d9e9 commit 3dc3eba

File tree

4 files changed

+37
-55
lines changed

4 files changed

+37
-55
lines changed

src/coreclr/jit/forwardsub.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,15 @@ bool Compiler::fgForwardSubStatement(Statement* stmt)
659659

660660
// Quirks:
661661
//
662+
// Don't substitute nodes "AddFinalArgsAndDetermineABIInfo" doesn't handle into struct args.
663+
//
664+
if (fsv.IsCallArg() && fsv.GetNode()->TypeIs(TYP_STRUCT) &&
665+
!fwdSubNode->OperIs(GT_OBJ, GT_LCL_VAR, GT_LCL_FLD, GT_MKREFANY))
666+
{
667+
JITDUMP(" use is a struct arg; fwd sub node is not OBJ/LCL_VAR/LCL_FLD/MKREFANY\n");
668+
return false;
669+
}
670+
662671
// We may sometimes lose or change a type handle. Avoid substituting if so.
663672
//
664673
// However, we allow free substitution of hardware SIMD types.

src/coreclr/jit/gentree.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,9 @@ ClassLayout* GenTree::GetLayout(Compiler* compiler) const
597597
case GT_BLK:
598598
return AsBlk()->GetLayout();
599599

600+
case GT_MKREFANY:
601+
return compiler->typGetObjLayout(compiler->impGetRefAnyClass());
602+
600603
default:
601604
unreached();
602605
}

src/coreclr/jit/lclmorph.cpp

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,10 +1049,9 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
10491049
return IndirTransform::None;
10501050
}
10511051

1052-
if ((user == nullptr) || !user->OperIs(GT_ASG, GT_RETURN))
1052+
if ((user == nullptr) || !user->OperIs(GT_ASG, GT_CALL, GT_RETURN))
10531053
{
1054-
// TODO-ADDR: call args require extra work because currently they must
1055-
// be wrapped in OBJ nodes so we can't replace those with local nodes.
1054+
// TODO-ADDR: remove unused indirections.
10561055
return IndirTransform::None;
10571056
}
10581057

@@ -1075,7 +1074,6 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
10751074
//
10761075
enum class StructMatch
10771076
{
1078-
Exact,
10791077
Compatible,
10801078
Partial
10811079
};
@@ -1084,44 +1082,44 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
10841082
assert(varDsc->GetLayout() != nullptr);
10851083

10861084
StructMatch match = StructMatch::Partial;
1087-
if (val.Offset() == 0)
1085+
if ((val.Offset() == 0) && ClassLayout::AreCompatible(indirLayout, varDsc->GetLayout()))
10881086
{
1089-
if (indirLayout->GetClassHandle() == varDsc->GetStructHnd())
1090-
{
1091-
match = StructMatch::Exact;
1092-
}
1093-
else if (ClassLayout::AreCompatible(indirLayout, varDsc->GetLayout()))
1094-
{
1095-
match = StructMatch::Compatible;
1096-
}
1087+
match = StructMatch::Compatible;
10971088
}
10981089

10991090
// Current matrix of matches/users/types:
11001091
//
1101-
// |------------|------|-------------|---------|
1102-
// | STRUCT | CALL | ASG | RETURN |
1103-
// |------------|------|-------------|---------|
1104-
// | Exact | None | LCL_VAR | LCL_VAR |
1105-
// | Compatible | None | LCL_VAR | LCL_VAR |
1106-
// | Partial | None | OBJ/LCL_FLD | LCL_FLD |
1107-
// |------------|------|-------------|---------|
1092+
// |------------|---------|-------------|---------|
1093+
// | STRUCT | CALL(*) | ASG | RETURN |
1094+
// |------------|---------|-------------|---------|
1095+
// | Compatible | LCL_VAR | LCL_VAR | LCL_VAR |
1096+
// | Partial | LCL_FLD | OBJ/LCL_FLD | LCL_FLD |
1097+
// |------------|---------|-------------|---------|
1098+
//
1099+
// * - On Windows x64 only.
11081100
//
11091101
// |------------|------|------|--------|----------|
11101102
// | SIMD | CALL | ASG | RETURN | HWI/SIMD |
11111103
// |------------|------|------|--------|----------|
1112-
// | Exact | None | None | None | None |
11131104
// | Compatible | None | None | None | None |
11141105
// | Partial | None | None | None | None |
11151106
// |------------|------|------|--------|----------|
11161107
//
11171108
// TODO-ADDR: delete all the "None" entries and always
11181109
// transform local nodes into LCL_VAR or LCL_FLD.
11191110

1120-
assert(indir->TypeIs(TYP_STRUCT) && user->OperIs(GT_ASG, GT_RETURN));
1111+
assert(indir->TypeIs(TYP_STRUCT) && user->OperIs(GT_ASG, GT_CALL, GT_RETURN));
11211112

11221113
*pStructLayout = indirLayout;
11231114

1124-
if ((match == StructMatch::Exact) || (match == StructMatch::Compatible))
1115+
if (user->IsCall())
1116+
{
1117+
#ifndef WINDOWS_AMD64_ABI
1118+
return IndirTransform::None;
1119+
#endif // !WINDOWS_AMD64_ABI
1120+
}
1121+
1122+
if (match == StructMatch::Compatible)
11251123
{
11261124
return IndirTransform::LclVar;
11271125
}

src/coreclr/jit/morph.cpp

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2347,30 +2347,9 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call
23472347
GenTree* actualArg = argx->gtEffectiveVal(true /* Commas only */);
23482348

23492349
// Here we look at "actualArg" to avoid calling "getClassSize".
2350-
if (actualArg->TypeGet() == TYP_STRUCT)
2351-
{
2352-
switch (actualArg->OperGet())
2353-
{
2354-
case GT_OBJ:
2355-
structSize = actualArg->AsObj()->Size();
2356-
break;
2357-
case GT_LCL_VAR:
2358-
structSize = comp->lvaGetDesc(actualArg->AsLclVarCommon())->lvExactSize;
2359-
break;
2360-
case GT_MKREFANY:
2361-
structSize = comp->info.compCompHnd->getClassSize(argSigClass);
2362-
break;
2363-
default:
2364-
BADCODE("illegal argument tree: cannot determine size for ABI handling");
2365-
break;
2366-
}
2367-
}
2368-
else
2369-
{
2370-
structSize = genTypeSize(actualArg);
2371-
}
2350+
structSize = actualArg->TypeIs(TYP_STRUCT) ? actualArg->GetLayout(comp)->GetSize() : genTypeSize(actualArg);
23722351

2373-
assert(structSize = comp->info.compCompHnd->getClassSize(argSigClass));
2352+
assert(structSize == comp->info.compCompHnd->getClassSize(argSigClass));
23742353
}
23752354
#if defined(TARGET_AMD64)
23762355
#ifdef UNIX_AMD64_ABI
@@ -3190,15 +3169,8 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
31903169
unsigned originalSize;
31913170
if (argObj->TypeGet() == TYP_STRUCT)
31923171
{
3193-
if (argObj->OperIs(GT_OBJ))
3194-
{
3195-
originalSize = argObj->AsObj()->Size();
3196-
}
3197-
else
3198-
{
3199-
// Must be LCL_VAR: we have a BADCODE assert for this in AddFinalArgsAndDetermineABIInfo.
3200-
originalSize = lvaGetDesc(argObj->AsLclVar())->lvExactSize;
3201-
}
3172+
assert(argObj->OperIs(GT_OBJ, GT_LCL_VAR, GT_LCL_FLD));
3173+
originalSize = argObj->GetLayout(this)->GetSize();
32023174
}
32033175
else
32043176
{

0 commit comments

Comments
 (0)