Skip to content

Commit

Permalink
Morph x86 stack args in LocalAddressVisitor
Browse files Browse the repository at this point in the history
  • Loading branch information
SingleAccretion committed May 28, 2022
1 parent 8512c37 commit 84df481
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 65 deletions.
13 changes: 13 additions & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -3257,6 +3257,19 @@ class Compiler
bool lvaIsOriginalThisReadOnly(); // return true if there is no place in the code
// that writes to arg0

#ifdef TARGET_X86
bool lvaIsArgAccessedViaVarArgsCookie(unsigned lclNum)
{
if (!info.compIsVarArgs)
{
return false;
}

LclVarDsc* varDsc = lvaGetDesc(lclNum);
return varDsc->lvIsParam && !varDsc->lvIsRegArg && (lclNum != lvaVarargsHandleArg);
}
#endif // TARGET_X86

// For x64 this is 3, 5, 6, 7, >8 byte structs that are passed by reference.
// For ARM64, this is structs larger than 16 bytes that are passed by reference.
bool lvaIsImplicitByRefLocal(unsigned varNum)
Expand Down
23 changes: 23 additions & 0 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23044,6 +23044,29 @@ uint16_t GenTreeLclVarCommon::GetLclOffs() const
}
}

//------------------------------------------------------------------------
// GetLayout: get the struct layout for a local node of struct type.
//
// Arguments:
// compiler - the compiler instance
//
// Return Value:
// If "this" is a local field node, the layout stored in the node,
// otherwise the layout of local itself.
//
ClassLayout* GenTreeLclVarCommon::GetLayout(Compiler* compiler) const
{
assert(varTypeIsStruct(TypeGet()));

if (OperIs(GT_LCL_VAR, GT_STORE_LCL_VAR))
{
return compiler->lvaGetDesc(GetLclNum())->GetLayout();
}

assert(OperIs(GT_LCL_FLD, GT_STORE_LCL_FLD));
return AsLclFld()->GetLayout();
}

#if defined(TARGET_XARCH) && defined(FEATURE_HW_INTRINSICS)
//------------------------------------------------------------------------
// GetResultOpNumForFMA: check if the result is written into one of the operands.
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -3284,6 +3284,8 @@ struct GenTreeLclVarCommon : public GenTreeUnOp

uint16_t GetLclOffs() const;

ClassLayout* GetLayout(Compiler* compiler) const;

unsigned GetSsaNum() const
{
return _gtSsaNum;
Expand Down
46 changes: 19 additions & 27 deletions src/coreclr/jit/lclmorph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -608,17 +608,27 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
bool hasHiddenStructArg = false;
if (m_compiler->opts.compJitOptimizeStructHiddenBuffer)
{
if (varTypeIsStruct(varDsc) && varDsc->lvIsTemp)
// We will only attempt this optimization for locals that are:
// a) Not susceptible to liveness bugs (see "lvaSetHiddenBufferStructArg").
// b) Do not later turn into indirections.
//
bool isSuitableLocal =
varTypeIsStruct(varDsc) && varDsc->lvIsTemp && !m_compiler->lvaIsImplicitByRefLocal(val.LclNum());
#ifdef TARGET_X86
if (m_compiler->lvaIsArgAccessedViaVarArgsCookie(val.LclNum()))
{
if ((callTree != nullptr) && callTree->gtArgs.HasRetBuffer() &&
(val.Node() == callTree->gtArgs.GetRetBufferArg()->GetNode()))
{
assert(!exposeParentLcl);
isSuitableLocal = false;
}
#endif // TARGET_X86

m_compiler->lvaSetHiddenBufferStructArg(val.LclNum());
hasHiddenStructArg = true;
callTree->gtCallMoreFlags |= GTF_CALL_M_RETBUFFARG_LCLOPT;
}
if (isSuitableLocal && (callTree != nullptr) && callTree->gtArgs.HasRetBuffer() &&
(val.Node() == callTree->gtArgs.GetRetBufferArg()->GetNode()))
{
assert(!exposeParentLcl);

m_compiler->lvaSetHiddenBufferStructArg(val.LclNum());
hasHiddenStructArg = true;
callTree->gtCallMoreFlags |= GTF_CALL_M_RETBUFFARG_LCLOPT;
}
}

Expand Down Expand Up @@ -838,15 +848,6 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
return;
}

#ifdef TARGET_X86
if (m_compiler->info.compIsVarArgs && varDsc->lvIsParam && !varDsc->lvIsRegArg)
{
// TODO-ADDR: For now we ignore all stack parameters of varargs methods,
// fgMorphStackArgForVarArgs does not handle LCL_VAR|FLD_ADDR nodes.
return;
}
#endif

GenTree* addr = val.Node();

if (val.Offset() > UINT16_MAX)
Expand Down Expand Up @@ -1029,15 +1030,6 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
return IndirTransform::None;
}

#ifdef TARGET_X86
if (m_compiler->info.compIsVarArgs && varDsc->lvIsParam && !varDsc->lvIsRegArg)
{
// TODO-ADDR: For now we ignore all stack parameters of varargs methods,
// fgMorphStackArgForVarArgs does not handle LCL_FLD nodes.
return IndirTransform::None;
}
#endif

// As we are only handling non-promoted STRUCT locals right now, the only
// possible transformation for non-STRUCT indirect uses is LCL_FLD.
if (!varTypeIsStruct(indir))
Expand Down
64 changes: 26 additions & 38 deletions src/coreclr/jit/morph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4898,12 +4898,11 @@ GenTree* Compiler::fgMorphLocal(GenTreeLclVarCommon* lclNode)

#ifdef TARGET_X86
//------------------------------------------------------------------------
// fgMorphExpandStackArgForVarArgs: Expand a local for a stack arg with varargs.
// fgMorphExpandStackArgForVarArgs: Expand a stack arg node for varargs.
//
// Expands the node to use the varargs cookie as the base address, indirecting
// off of it if necessary, similar to how implicit by-ref parameters are morphed.
//
// This transformation is only needed on x86.
// off of it if necessary, similar to how implicit by-ref parameters are morphed
// on non-x86 targets.
//
// Arguments:
// lclNode - The local node to (possibly) morph
Expand All @@ -4914,50 +4913,39 @@ GenTree* Compiler::fgMorphLocal(GenTreeLclVarCommon* lclNode)
//
GenTree* Compiler::fgMorphExpandStackArgForVarArgs(GenTreeLclVarCommon* lclNode)
{
if (!info.compIsVarArgs)
if (!lvaIsArgAccessedViaVarArgsCookie(lclNode->GetLclNum()))
{
return nullptr;
}

unsigned lclNum = lclNode->GetLclNum();
LclVarDsc* varDsc = lvaGetDesc(lclNode);
LclVarDsc* varDsc = lvaGetDesc(lclNode);
GenTree* argsBaseAddr = gtNewLclvNode(lvaVarargsBaseOfStkArgs, TYP_I_IMPL);
ssize_t offset =
varDsc->GetStackOffset() - codeGen->intRegState.rsCalleeRegArgCount * REGSIZE_BYTES - lclNode->GetLclOffs();
GenTree* offsetNode = gtNewIconNode(offset, TYP_I_IMPL);
GenTree* argAddr = gtNewOperNode(GT_SUB, TYP_I_IMPL, argsBaseAddr, offsetNode);

if (varDsc->lvIsParam && !varDsc->lvIsRegArg && (lclNum != lvaVarargsHandleArg))
if (lclNode->OperIsLocalAddr())
{
// Create the tree pointing at this argument.
GenTree* argsBaseAddr = gtNewLclvNode(lvaVarargsBaseOfStkArgs, TYP_I_IMPL);
GenTree* offsetNode = gtNewIconNode(varDsc->GetStackOffset() -
codeGen->intRegState.rsCalleeRegArgCount * REGSIZE_BYTES -
lclNode->GetLclOffs(), TYP_I_IMPL);
GenTree* argAddr = gtNewOperNode(GT_SUB, TYP_I_IMPL, argsBaseAddr, offsetNode);

if (lclNode->OperIsLocalAddr())
{
return argAddr;
}

// Access the argument through an indirection.
GenTree* argNode;
if (varTypeIsStruct(lclNode))
{
// TODO-ADDR: update this once TYP_STRUCT LCL_FLD is supported.
assert(lclNode->OperIs(GT_LCL_VAR));
argNode = gtNewObjNode(varDsc->GetLayout(), argAddr);
}
else
{
argNode = gtNewIndir(lclNode->TypeGet(), argAddr);
}
return argAddr;
}

if (varDsc->IsAddressExposed())
{
argNode->gtFlags |= GTF_GLOB_REF;
}
GenTree* argNode;
if (varTypeIsStruct(lclNode))
{
argNode = gtNewObjNode(lclNode->GetLayout(this), argAddr);
}
else
{
argNode = gtNewIndir(lclNode->TypeGet(), argAddr);
}

return argNode;
if (varDsc->IsAddressExposed())
{
argNode->gtFlags |= GTF_GLOB_REF;
}

return nullptr;
return argNode;
}
#endif

Expand Down

0 comments on commit 84df481

Please sign in to comment.