From 1d4b0f697202e8e47347058fd87849cf7ea7480e Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Tue, 11 Oct 2022 18:35:20 +0200 Subject: [PATCH] JIT: Fix profiler tail call insertion logic for FIELD_LIST This logic was not handling FIELD_LIST and was also not handling linear order appropriately. The logic is still a bit odd, it would probably be better to use the same kind of logic as CFG (moving PUTARG nodes ahead of the profiler hook instead), but in practice this seems to be ok. Fix #76879 --- src/coreclr/jit/lower.cpp | 111 +++++++++++++++++++++++++++++--------- src/coreclr/jit/lower.h | 2 + 2 files changed, 87 insertions(+), 26 deletions(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 5c09733806790..947b0f7a77d2f 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -1711,45 +1711,104 @@ void Lowering::InsertProfTailCallHook(GenTreeCall* call, GenTree* insertionPoint if (insertionPoint == nullptr) { - for (CallArg& arg : call->gtArgs.EarlyArgs()) - { - assert(!arg.GetEarlyNode()->OperIs(GT_PUTARG_REG)); // We don't expect to see these in early args - - if (arg.GetEarlyNode()->OperIs(GT_PUTARG_STK)) - { - // found it - insertionPoint = arg.GetEarlyNode(); - break; - } - } + insertionPoint = FindEarliestPutArg(call); if (insertionPoint == nullptr) { - for (CallArg& arg : call->gtArgs.LateArgs()) - { - if (arg.GetLateNode()->OperIs(GT_PUTARG_REG, GT_PUTARG_STK)) - { - // found it - insertionPoint = arg.GetLateNode(); - break; - } - } - - // If there are no args, insert before the call node - if (insertionPoint == nullptr) - { - insertionPoint = call; - } + insertionPoint = call; } } #endif // !defined(TARGET_X86) assert(insertionPoint != nullptr); + JITDUMP("Inserting profiler tail call before [%06u]\n", comp->dspTreeID(insertionPoint)); + GenTree* profHookNode = new (comp, GT_PROF_HOOK) GenTree(GT_PROF_HOOK, TYP_VOID); BlockRange().InsertBefore(insertionPoint, profHookNode); } +//------------------------------------------------------------------------ +// FindEarliestPutArg: Find the earliest direct PUTARG operand of a call node in +// linear order. +// +// Arguments: +// call - the call +// +// Returns: +// A PUTARG_* node that is the earliest of the call, or nullptr if the call +// has no arguments. +// +GenTree* Lowering::FindEarliestPutArg(GenTreeCall* call) +{ + size_t numMarkedNodes = 0; + for (CallArg& arg : call->gtArgs.Args()) + { + GenTree* earlyNode = arg.GetEarlyNode(); + if (arg.GetEarlyNode() != nullptr) + { + numMarkedNodes += MarkPutArgNodes(arg.GetEarlyNode()); + } + + if (arg.GetLateNode() != nullptr) + { + numMarkedNodes += MarkPutArgNodes(arg.GetLateNode()); + } + } + + if (numMarkedNodes <= 0) + { + return nullptr; + } + + GenTree* node = call->gtPrev; + do + { + node = node->gtPrev; + + assert((node != nullptr) && "Reached beginning of basic block while looking for marked nodes"); + + if ((node->gtLIRFlags & LIR::Flags::Mark) != 0) + { + node->gtLIRFlags &= ~LIR::Flags::Mark; + numMarkedNodes--; + } + } while (numMarkedNodes > 0); + + return node; +} + +//------------------------------------------------------------------------ +// MarkPutArgNodes: Mark all direct operand PUTARG nodes with a LIR mark. +// +// Arguments: +// node - the node (either a field list or PUTARG node) +// +// Returns: +// The number of marks added. +// +size_t Lowering::MarkPutArgNodes(GenTree* node) +{ + assert(node->OperIsPutArg() || node->OperIsFieldList()); + + size_t result = 0; + if (node->OperIsFieldList()) + { + for (GenTreeFieldList::Use& operand : node->AsFieldList()->Uses()) + { + assert(operand.GetNode()->OperIsPutArg()); + result += MarkPutArgNodes(operand.GetNode()); + } + } + else + { + node->gtLIRFlags |= LIR::Flags::Mark; + result++; + } + + return result; +} + //------------------------------------------------------------------------ // LowerFastTailCall: Lower a call node dispatched as a fast tailcall (epilog + // jmp). diff --git a/src/coreclr/jit/lower.h b/src/coreclr/jit/lower.h index f37aa6d2be5e0..84ba314adc514 100644 --- a/src/coreclr/jit/lower.h +++ b/src/coreclr/jit/lower.h @@ -161,6 +161,8 @@ class Lowering final : public Phase GenTree* lookForUsesStart, GenTreeCall* callNode); void InsertProfTailCallHook(GenTreeCall* callNode, GenTree* insertionPoint); + GenTree* FindEarliestPutArg(GenTreeCall* call); + size_t MarkPutArgNodes(GenTree* node); GenTree* LowerVirtualVtableCall(GenTreeCall* call); GenTree* LowerVirtualStubCall(GenTreeCall* call); void LowerArgsForCall(GenTreeCall* call);