From 3dc3ebaa245af922042520f7d095fb80070f5e31 Mon Sep 17 00:00:00 2001 From: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> Date: Sun, 19 Jun 2022 23:44:36 +0300 Subject: [PATCH] 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 --- src/coreclr/jit/forwardsub.cpp | 9 +++++++++ src/coreclr/jit/gentree.cpp | 3 +++ src/coreclr/jit/lclmorph.cpp | 44 ++++++++++++++++++++---------------------- src/coreclr/jit/morph.cpp | 36 ++++------------------------------ 4 files changed, 37 insertions(+), 55 deletions(-) diff --git a/src/coreclr/jit/forwardsub.cpp b/src/coreclr/jit/forwardsub.cpp index 4da3c62..e6e2c84 100644 --- a/src/coreclr/jit/forwardsub.cpp +++ b/src/coreclr/jit/forwardsub.cpp @@ -659,6 +659,15 @@ bool Compiler::fgForwardSubStatement(Statement* stmt) // Quirks: // + // Don't substitute nodes "AddFinalArgsAndDetermineABIInfo" doesn't handle into struct args. + // + if (fsv.IsCallArg() && fsv.GetNode()->TypeIs(TYP_STRUCT) && + !fwdSubNode->OperIs(GT_OBJ, GT_LCL_VAR, GT_LCL_FLD, GT_MKREFANY)) + { + JITDUMP(" use is a struct arg; fwd sub node is not OBJ/LCL_VAR/LCL_FLD/MKREFANY\n"); + return false; + } + // We may sometimes lose or change a type handle. Avoid substituting if so. // // However, we allow free substitution of hardware SIMD types. diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 0f749b1..19e551f 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -597,6 +597,9 @@ ClassLayout* GenTree::GetLayout(Compiler* compiler) const case GT_BLK: return AsBlk()->GetLayout(); + case GT_MKREFANY: + return compiler->typGetObjLayout(compiler->impGetRefAnyClass()); + default: unreached(); } diff --git a/src/coreclr/jit/lclmorph.cpp b/src/coreclr/jit/lclmorph.cpp index 5629c19..3b1b635 100644 --- a/src/coreclr/jit/lclmorph.cpp +++ b/src/coreclr/jit/lclmorph.cpp @@ -1049,10 +1049,9 @@ private: return IndirTransform::None; } - if ((user == nullptr) || !user->OperIs(GT_ASG, GT_RETURN)) + if ((user == nullptr) || !user->OperIs(GT_ASG, GT_CALL, GT_RETURN)) { - // TODO-ADDR: call args require extra work because currently they must - // be wrapped in OBJ nodes so we can't replace those with local nodes. + // TODO-ADDR: remove unused indirections. return IndirTransform::None; } @@ -1075,7 +1074,6 @@ private: // enum class StructMatch { - Exact, Compatible, Partial }; @@ -1084,32 +1082,25 @@ private: assert(varDsc->GetLayout() != nullptr); StructMatch match = StructMatch::Partial; - if (val.Offset() == 0) + if ((val.Offset() == 0) && ClassLayout::AreCompatible(indirLayout, varDsc->GetLayout())) { - if (indirLayout->GetClassHandle() == varDsc->GetStructHnd()) - { - match = StructMatch::Exact; - } - else if (ClassLayout::AreCompatible(indirLayout, varDsc->GetLayout())) - { - match = StructMatch::Compatible; - } + match = StructMatch::Compatible; } // Current matrix of matches/users/types: // - // |------------|------|-------------|---------| - // | STRUCT | CALL | ASG | RETURN | - // |------------|------|-------------|---------| - // | Exact | None | LCL_VAR | LCL_VAR | - // | Compatible | None | LCL_VAR | LCL_VAR | - // | Partial | None | OBJ/LCL_FLD | LCL_FLD | - // |------------|------|-------------|---------| + // |------------|---------|-------------|---------| + // | STRUCT | CALL(*) | ASG | RETURN | + // |------------|---------|-------------|---------| + // | Compatible | LCL_VAR | LCL_VAR | LCL_VAR | + // | Partial | LCL_FLD | OBJ/LCL_FLD | LCL_FLD | + // |------------|---------|-------------|---------| + // + // * - On Windows x64 only. // // |------------|------|------|--------|----------| // | SIMD | CALL | ASG | RETURN | HWI/SIMD | // |------------|------|------|--------|----------| - // | Exact | None | None | None | None | // | Compatible | None | None | None | None | // | Partial | None | None | None | None | // |------------|------|------|--------|----------| @@ -1117,11 +1108,18 @@ private: // TODO-ADDR: delete all the "None" entries and always // transform local nodes into LCL_VAR or LCL_FLD. - assert(indir->TypeIs(TYP_STRUCT) && user->OperIs(GT_ASG, GT_RETURN)); + assert(indir->TypeIs(TYP_STRUCT) && user->OperIs(GT_ASG, GT_CALL, GT_RETURN)); *pStructLayout = indirLayout; - if ((match == StructMatch::Exact) || (match == StructMatch::Compatible)) + if (user->IsCall()) + { +#ifndef WINDOWS_AMD64_ABI + return IndirTransform::None; +#endif // !WINDOWS_AMD64_ABI + } + + if (match == StructMatch::Compatible) { return IndirTransform::LclVar; } diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 16ef004..f8c7b08 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -2347,30 +2347,9 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call GenTree* actualArg = argx->gtEffectiveVal(true /* Commas only */); // Here we look at "actualArg" to avoid calling "getClassSize". - if (actualArg->TypeGet() == TYP_STRUCT) - { - switch (actualArg->OperGet()) - { - case GT_OBJ: - structSize = actualArg->AsObj()->Size(); - break; - case GT_LCL_VAR: - structSize = comp->lvaGetDesc(actualArg->AsLclVarCommon())->lvExactSize; - break; - case GT_MKREFANY: - structSize = comp->info.compCompHnd->getClassSize(argSigClass); - break; - default: - BADCODE("illegal argument tree: cannot determine size for ABI handling"); - break; - } - } - else - { - structSize = genTypeSize(actualArg); - } + structSize = actualArg->TypeIs(TYP_STRUCT) ? actualArg->GetLayout(comp)->GetSize() : genTypeSize(actualArg); - assert(structSize = comp->info.compCompHnd->getClassSize(argSigClass)); + assert(structSize == comp->info.compCompHnd->getClassSize(argSigClass)); } #if defined(TARGET_AMD64) #ifdef UNIX_AMD64_ABI @@ -3190,15 +3169,8 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call) unsigned originalSize; if (argObj->TypeGet() == TYP_STRUCT) { - if (argObj->OperIs(GT_OBJ)) - { - originalSize = argObj->AsObj()->Size(); - } - else - { - // Must be LCL_VAR: we have a BADCODE assert for this in AddFinalArgsAndDetermineABIInfo. - originalSize = lvaGetDesc(argObj->AsLclVar())->lvExactSize; - } + assert(argObj->OperIs(GT_OBJ, GT_LCL_VAR, GT_LCL_FLD)); + originalSize = argObj->GetLayout(this)->GetSize(); } else { -- 2.7.4