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

Code before:
    {
        DebugInfo di;
        (void)compiler->genCallSite2DebugInfoMap->Lookup(call, &di);
        params.debugInfo = di;
    }

#ifdef DEBUG
    // Pass the call signature information down into the emitter so the emitter can associate
    // native call sites with the signatures they were generated from.
    if (!call->IsHelperCall())
    {
        params.sigInfo = call->callSig;
    }
#endif // DEBUG
    GenTree* target = getCallTarget(call, &params.methHnd);

    if (target != nullptr)
    {
        // A call target can not be a contained indirection
        assert(!target->isContainedIndir());

        // Codegen should have already evaluated our target node (last) and pushed it onto the stack,
        //  ready for call_indirect. Consume it.
        genConsumeReg(target);

        if (target->isContainedIntOrIImmed())
        {
            NYI_WASM("Contained int or iimmed call target");
        }
        else
        {
            params.callType = EC_INDIR_R;
            // TODO-WASM: Figure out whether we need this. I think the target should always be on stack, not in a local.
            // params.ireg     = target->GetRegNum();
        }

        // TODO-WASM: Assert disabled due to above
        // assert(genIsValidIntReg(params.ireg));

        genEmitCallWithCurrentGC(params);
    }
    else
    {
        // If we have no target and this is a call with indirection cell then
        // we do an optimization where we load the call address directly from
        // the indirection cell instead of duplicating the tree. In BuildCall
        // we ensure that get an extra register for the purpose. Note that for
        // CFG the call might have changed to
        // CORINFO_HELP_DISPATCH_INDIRECT_CALL in which case we still have the
        // indirection cell but we should not try to optimize.
        WellKnownArg indirectionCellArgKind = WellKnownArg::None;

Review comment (refactor):
This part of the code doesn't look right. On native platforms:
1) We have a call with a known target address which also happens to have an indirection cell arg (typical example is interface dispatch).
2) Without the optimization, we'd generate:
```
mov r13, <cell> ; it is a constant
mov r14, <cell> ; duplicated here
ld  r14, [r14]
call r14
```
3) With the optimization, we get rid of `mov r14, <cell>` and use `r13` directly in `ld r14, [r13]`.

Now, this is perfectly translatable to WASM as well, where we could have, say:
```
i32.const <cell>
local.tee cell
local.get cell
i32.load
```
Instead of:
```
i32.const <cell>
i32.const <cell>
i32.load
```
But the current code doesn't do this.

I would propose to do this optimization in lowering with regular IR instead seeing as we don't have something like `targetAddrReg`. It would also get rid of the assumption that the indirection cell arg is last. It implies removing this special case and adding `#ifndef TARGET_WASM` in `LowerCall` around `if (!hasIndirectionCell)`.

Code after:

    if (target != nullptr)
    {
        // Codegen should have already evaluated our target node (last) and pushed it onto the stack,
        //  ready for call_indirect. Consume it.
        genConsumeReg(target);

        params.callType = EC_INDIR_R;
        genEmitCallWithCurrentGC(params);
    }
    else
    {
        // If we have no target and this is a call with indirection cell then
        // we do an optimization where we load the call address directly from
        // the indirection cell instead of duplicating the tree. In BuildCall
        // we ensure that get an extra register for the purpose. Note that for
        // CFG the call might have changed to
        // CORINFO_HELP_DISPATCH_INDIRECT_CALL in which case we still have the
        // indirection cell but we should not try to optimize.
        WellKnownArg indirectionCellArgKind = WellKnownArg::None;
        if (!call->IsHelperCall(compiler, CORINFO_HELP_DISPATCH_INDIRECT_CALL))
        {
            indirectionCellArgKind = call->GetIndirectionCellArgKind();
        }

        if (indirectionCellArgKind != WellKnownArg::None)
        {
            assert(call->IsR2ROrVirtualStubRelativeIndir());

            params.callType = EC_INDIR_R;
            // params.ireg     = targetAddrReg;
            genEmitCallWithCurrentGC(params);
        }
        else
        {
            // Generate a direct call to a non-virtual user defined or helper method
            assert(call->IsHelperCall() || (call->gtCallType == CT_USER_FUNC));

            assert(call->gtEntryPoint.addr == NULL);

            if (call->IsHelperCall())
            {
                NYI_WASM("Call helper statically without indirection cell");
                CorInfoHelpFunc helperNum = compiler->eeGetHelperNum(params.methHnd);
                noway_assert(helperNum != CORINFO_HELP_UNDEF);

                CORINFO_CONST_LOOKUP helperLookup = compiler->compGetHelperFtn(helperNum);
                params.addr                       = helperLookup.addr;
                assert(helperLookup.accessType == IAT_VALUE);
            }
            else