Repository: dotnet/runtime
File: src/coreclr/jit/lowerwasm.cpp (C++)

Code before:
            return current->gtPrev;
        }

        bool IsDataFlowRoot(GenTree* node)
        {
            return !node->IsValue() || node->IsUnusedValue();
        }
    };

    Stackifier stackifier(this);
    stackifier.StackifyCurrentBlock();
}

//------------------------------------------------------------------------
// AfterLowerLclHeap: target-specific post-processing of the lowered LCLHEAP.
//
// Arguments:
//    treeNode - the GT_LCLHEAP node that was just lowered.
//
void Lowering::AfterLowerLclHeap(GenTree* treeNode)
{
    GenTree* size = treeNode->AsOp()->gtOp1;

    if (!size->isContainedIntOrIImmed())
    {
        size = m_compiler->gtNewCastNode(TYP_I_IMPL, size, false, TYP_I_IMPL);
        BlockRange().InsertBefore(treeNode, size);
        treeNode->AsOp()->gtOp1 = size;
        size->gtLIRFlags |= LIR::Flags::MultiplyUsed;
    }
}

//------------------------------------------------------------------------
// AfterLowerArgsForCall: post processing after call args are lowered
//
// Arguments:
//    call - Call node
//
void Lowering::AfterLowerArgsForCall(GenTreeCall* call)
{
    if (call->NeedsNullCheck())
    {
        // Prepare for explicit null check
        CallArg* thisArg = call->gtArgs.GetThisArg();
        thisArg->GetNode()->gtLIRFlags |= LIR::Flags::MultiplyUsed;
    }
}


Review comment (suggestion):
For 32 bit WASM `TYP_I_IMPL == TYP_INT`. So a no-op.

Also, should this be an unsigned cast?

Also, this would deserve a comment as to why we're deciding to add a cast here (| why is it better than the alternatives).

Code after:
    {
        Lowering* m_lower;
        bool      m_anyChanges = false;

    public:
        Stackifier(Lowering* lower)
            : m_lower(lower)
        {
        }

        void StackifyCurrentBlock()
        {
            GenTree* node = m_lower->BlockRange().LastNode();
            while (node != nullptr)
            {
                assert(IsDataFlowRoot(node));
                node = StackifyTree(node);
            }

            if (!m_anyChanges)
            {
                JITDUMP(FMT_BB ": already in WASM value stack order\n", m_lower->m_block->bbNum);
            }
        }

        GenTree* StackifyTree(GenTree* root)
        {
            ArrayStack<GenTree*>* stack        = &m_lower->m_stackificationStack;
            int                   initialDepth = stack->Height();

            // Simple greedy algorithm working backwards. The invariant is that the stack top must be placed right next
            // to (in normal linear order - before) the node we last stackified.
            stack->Push(root);
            GenTree* current = root->gtNext;
            while (stack->Height() != initialDepth)
            {
                GenTree* node = stack->Pop();
                GenTree* prev = (current != nullptr) ? current->gtPrev : root;
                while (node != prev)
                {
                    // Maybe this is an intervening void-equivalent node that we can also just stackify.
                    if (IsDataFlowRoot(prev))
                    {
                        prev = StackifyTree(prev);
                        continue;
                    }

                    // At this point, we'll have to modify the IR in some way. In general, these cases should be quite
                    // rare, introduced in lowering only. All HIR-induced cases (such as from "gtSetEvalOrder") should
                    // instead be ifdef-ed out for WASM.
                    m_anyChanges = true;