Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions src/coreclr/jit/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1432,8 +1432,8 @@ bool BasicBlock::endsWithJmpMethod(Compiler* comp) const
//
bool BasicBlock::endsWithTailCallOrJmp(Compiler* comp, bool fastTailCallsOnly /*=false*/) const
{
GenTree* tailCall = nullptr;
bool tailCallsConvertibleToLoopOnly = false;
GenTreeCall* tailCall = nullptr;
bool tailCallsConvertibleToLoopOnly = false;
return endsWithJmpMethod(comp) ||
endsWithTailCall(comp, fastTailCallsOnly, tailCallsConvertibleToLoopOnly, &tailCall);
}
Expand All @@ -1454,10 +1454,10 @@ bool BasicBlock::endsWithTailCallOrJmp(Compiler* comp, bool fastTailCallsOnly /*
// Notes:
// At most one of fastTailCallsOnly and tailCallsConvertibleToLoopOnly flags can be true.
//
bool BasicBlock::endsWithTailCall(Compiler* comp,
bool fastTailCallsOnly,
bool tailCallsConvertibleToLoopOnly,
GenTree** tailCall) const
bool BasicBlock::endsWithTailCall(Compiler* comp,
bool fastTailCallsOnly,
bool tailCallsConvertibleToLoopOnly,
GenTreeCall** tailCall) const
{
assert(!fastTailCallsOnly || !tailCallsConvertibleToLoopOnly);
*tailCall = nullptr;
Expand Down Expand Up @@ -1524,7 +1524,7 @@ bool BasicBlock::endsWithTailCall(Compiler* comp,
// Return Value:
// true if the block ends with a tail call convertible to loop.
//
bool BasicBlock::endsWithTailCallConvertibleToLoop(Compiler* comp, GenTree** tailCall) const
bool BasicBlock::endsWithTailCallConvertibleToLoop(Compiler* comp, GenTreeCall** tailCall) const
{
bool fastTailCallsOnly = false;
bool tailCallsConvertibleToLoopOnly = true;
Expand Down
10 changes: 5 additions & 5 deletions src/coreclr/jit/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -1765,14 +1765,14 @@ struct BasicBlock : private LIR::Range

bool endsWithJmpMethod(Compiler* comp) const;

bool endsWithTailCall(Compiler* comp,
bool fastTailCallsOnly,
bool tailCallsConvertibleToLoopOnly,
GenTree** tailCall) const;
bool endsWithTailCall(Compiler* comp,
bool fastTailCallsOnly,
bool tailCallsConvertibleToLoopOnly,
GenTreeCall** tailCall) const;

bool endsWithTailCallOrJmp(Compiler* comp, bool fastTailCallsOnly = false) const;

bool endsWithTailCallConvertibleToLoop(Compiler* comp, GenTree** tailCall) const;
bool endsWithTailCallConvertibleToLoop(Compiler* comp, GenTreeCall** tailCall) const;

// Returns the first statement in the statement list of "this" that is
// not an SSA definition (a lcl = phi(...) store).
Expand Down
6 changes: 0 additions & 6 deletions src/coreclr/jit/codegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9557,9 +9557,6 @@ void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed)
0, // argSize. Again, we have to lie about it
EA_UNKNOWN); // retSize

// Check that we have place for the push.
assert(compiler->fgGetPtrArgCntMax() >= 1);
Comment on lines -9560 to -9561
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure what the comment is referring to. This value has not been used to allocate anything by the backend. The only thing it is used for is deciding between EBP/ESP frame and whether we need to switch to partial interruptible mode, but that's all done during StackLevelSetter.


#if defined(UNIX_X86_ABI)
// Restoring alignment manually. This is similar to CodeGen::genRemoveAlignmentAfterCall
GetEmitter()->emitIns_R_I(INS_add, EA_4BYTE, REG_SPBASE, 0x10);
Expand Down Expand Up @@ -9638,9 +9635,6 @@ void CodeGen::genProfilingLeaveCallback(unsigned helper)
#endif
genEmitHelperCall(helper, argSize, EA_UNKNOWN /* retSize */);

// Check that we have place for the push.
assert(compiler->fgGetPtrArgCntMax() >= 1);

#if defined(UNIX_X86_ABI)
// Restoring alignment manually. This is similar to CodeGen::genRemoveAlignmentAfterCall
GetEmitter()->emitIns_R_I(INS_add, EA_4BYTE, REG_SPBASE, 0x10);
Expand Down
27 changes: 0 additions & 27 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -6698,33 +6698,6 @@ class Compiler

//------------------------- Morphing --------------------------------------

unsigned fgPtrArgCntMax = 0;

public:
//------------------------------------------------------------------------
// fgGetPtrArgCntMax: Return the maximum number of pointer-sized stack arguments that calls inside this method
// can push on the stack. This value is calculated during morph.
//
// Return Value:
// Returns fgPtrArgCntMax, that is a private field.
//
unsigned fgGetPtrArgCntMax() const
{
return fgPtrArgCntMax;
}

//------------------------------------------------------------------------
// fgSetPtrArgCntMax: Set the maximum number of pointer-sized stack arguments that calls inside this method
// can push on the stack. This function is used during StackLevelSetter to fix incorrect morph calculations.
//
void fgSetPtrArgCntMax(unsigned argCntMax)
{
fgPtrArgCntMax = argCntMax;
}

bool compCanEncodePtrArgCntMax();

private:
hashBv* fgAvailableOutgoingArgTemps;
ArrayStack<unsigned>* fgUsedSharedTemps = nullptr;

Expand Down
14 changes: 0 additions & 14 deletions src/coreclr/jit/compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3024,20 +3024,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
*/

inline bool Compiler::compCanEncodePtrArgCntMax()
{
#ifdef JIT32_GCENCODER
// DDB 204533:
// The GC encoding for fully interruptible methods does not
// support more than 1023 pushed arguments, so we have to
// use a partially interruptible GC info/encoding.
//
return (fgPtrArgCntMax < MAX_PTRARG_OFS);
#else // JIT32_GCENCODER
return true;
#endif
}

/*****************************************************************************
*
* Call the given function pointer for all nodes in the tree. The 'visitor'
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/flowgraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4019,7 +4019,7 @@ PhaseStatus Compiler::fgSetBlockOrder()
BasicBlock::s_nMaxTrees = 0;
#endif

if (compCanEncodePtrArgCntMax() && fgHasCycleWithoutGCSafePoint())
if (fgHasCycleWithoutGCSafePoint())
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fgPtrArgCntMax is computed much after this, so the check was always true.

{
JITDUMP("Marking method as fully interruptible\n");
SetInterruptible(true);
Expand Down
33 changes: 33 additions & 0 deletions src/coreclr/jit/lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10942,5 +10942,38 @@ void Lowering::FinalizeOutgoingArgSpace()
comp->lvaOutgoingArgSpaceSize = m_outgoingArgSpaceSize;
comp->lvaOutgoingArgSpaceSize.MarkAsReadOnly();
comp->lvaGetDesc(comp->lvaOutgoingArgSpaceVar)->GrowBlockLayout(comp->typGetBlkLayout(m_outgoingArgSpaceSize));

SetFramePointerFromArgSpaceSize();
#endif
}

//----------------------------------------------------------------------------------------------
// Lowering::SetFramePointerFromArgSpaceSize:
// Set the frame pointer from the arg space size. This is a quirk because
// StackLevelSetter used to do this even outside x86.
//
void Lowering::SetFramePointerFromArgSpaceSize()
{
unsigned stackLevelSpace = m_outgoingArgSpaceSize;

if (comp->compTailCallUsed)
{
// StackLevelSetter also used to count tailcalls.
for (BasicBlock* block : comp->Blocks())
{
GenTreeCall* tailCall;
if (block->endsWithTailCall(comp, true, false, &tailCall))
{
stackLevelSpace = max(stackLevelSpace, tailCall->gtArgs.OutgoingArgsStackSize());
}
}
}

unsigned stackLevel =
(max(stackLevelSpace, (unsigned)MIN_ARG_AREA_FOR_CALL) - MIN_ARG_AREA_FOR_CALL) / TARGET_POINTER_SIZE;

if (stackLevel >= 4)
{
comp->codeGen->setFramePointerRequired(true);
}
}
1 change: 1 addition & 0 deletions src/coreclr/jit/lower.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class Lowering final : public Phase
}

void FinalizeOutgoingArgSpace();
void SetFramePointerFromArgSpaceSize();

private:
// LowerRange handles new code that is introduced by or after Lowering.
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/jit/morph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13148,10 +13148,10 @@ void Compiler::fgMorphStmts(BasicBlock* block)
}

#if FEATURE_FASTTAILCALL
GenTree* recursiveTailCall = nullptr;
GenTreeCall* recursiveTailCall = nullptr;
if (block->endsWithTailCallConvertibleToLoop(this, &recursiveTailCall))
{
fgMorphRecursiveFastTailCallIntoLoop(block, recursiveTailCall->AsCall());
fgMorphRecursiveFastTailCallIntoLoop(block, recursiveTailCall);
}
#endif

Expand Down
56 changes: 37 additions & 19 deletions src/coreclr/jit/stacklevelsetter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,15 @@ StackLevelSetter::StackLevelSetter(Compiler* compiler)
}

//------------------------------------------------------------------------
// DoPhase: Calculate stack slots numbers for outgoing args.
// DoPhase: Calculate stack slots numbers for outgoing args and compute
// requirements of throw helper blocks.
//
// Returns:
// PhaseStatus indicating what, if anything, was changed.
//
// Notes:
// For non-x86 platforms it calculates the max number of slots
// that calls inside this method can push on the stack.
// This value is used for sanity checks in the emitter.
//
// Stack slots are pointer-sized: 4 bytes for 32-bit platforms, 8 bytes for 64-bit platforms.
//
// For x86 it also sets throw-helper blocks incoming stack depth and set
// framePointerRequired when it is necessary. These values are used to pop
// pushed args when an exception occurs.
//
PhaseStatus StackLevelSetter::DoPhase()
{
for (BasicBlock* const block : comp->Blocks())
{
ProcessBlock(block);
}
ProcessBlocks();

#if !FEATURE_FIXED_OUT_ARGS
if (framePointerRequired)
Expand All @@ -56,7 +43,6 @@ PhaseStatus StackLevelSetter::DoPhase()

CheckAdditionalArgs();

comp->fgSetPtrArgCntMax(maxStackLevel);
CheckArgCnt();

// When optimizing, check if there are any unused throw helper blocks,
Expand Down Expand Up @@ -109,7 +95,28 @@ PhaseStatus StackLevelSetter::DoPhase()
}

//------------------------------------------------------------------------
// ProcessBlock: Do stack level calculations for one block.
// ProcessBlocks: Process all the blocks if necessary.
//
void StackLevelSetter::ProcessBlocks()
{
#ifndef TARGET_X86
// Outside x86 we do not need to compute pushed/popped stack slots.
// However, we do optimize throw-helpers and need to process the blocks for
// that, but only when optimizing.
if (!throwHelperBlocksUsed || comp->opts.OptimizationDisabled())
{
return;
}
#endif

for (BasicBlock* const block : comp->Blocks())
{
ProcessBlock(block);
}
}

//------------------------------------------------------------------------
// ProcessBlock: Do stack level and throw helper determinations for one block.
//
// Notes:
// Block starts and ends with an empty outgoing stack.
Expand All @@ -125,10 +132,13 @@ PhaseStatus StackLevelSetter::DoPhase()
void StackLevelSetter::ProcessBlock(BasicBlock* block)
{
assert(currentStackLevel == 0);

LIR::ReadOnlyRange& range = LIR::AsRange(block);
for (auto i = range.rbegin(); i != range.rend(); ++i)
{
GenTree* node = *i;

#ifdef TARGET_X86
if (node->OperIsPutArgStkOrSplit())
{
GenTreePutArgStk* putArg = node->AsPutArgStk();
Expand All @@ -145,6 +155,7 @@ void StackLevelSetter::ProcessBlock(BasicBlock* block)
call->gtArgs.SetStkSizeBytes(usedStackSlotsCount * TARGET_POINTER_SIZE);
#endif // UNIX_X86_ABI
}
#endif

if (!throwHelperBlocksUsed)
{
Expand Down Expand Up @@ -410,7 +421,12 @@ void StackLevelSetter::SubStackLevel(unsigned value)
//
void StackLevelSetter::CheckArgCnt()
{
if (!comp->compCanEncodePtrArgCntMax())
#ifdef JIT32_GCENCODER
// The GC encoding for fully interruptible methods does not
// support more than 1023 pushed arguments, so we have to
// use a partially interruptible GC info/encoding.
//
if (maxStackLevel >= MAX_PTRARG_OFS)
{
#ifdef DEBUG
if (comp->verbose)
Expand All @@ -421,6 +437,7 @@ void StackLevelSetter::CheckArgCnt()
#endif
comp->SetInterruptible(false);
}

if (maxStackLevel >= sizeof(unsigned))
{
#ifdef DEBUG
Expand All @@ -431,6 +448,7 @@ void StackLevelSetter::CheckArgCnt()
#endif
comp->codeGen->setFramePointerRequired(true);
}
#endif
}

//------------------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/stacklevelsetter.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class StackLevelSetter final : public Phase
virtual PhaseStatus DoPhase() override;

private:
void ProcessBlocks();
void ProcessBlock(BasicBlock* block);

void SetThrowHelperBlocks(GenTree* node, BasicBlock* block);
Expand Down
Loading