@@ -370,9 +370,15 @@ void CodeGen::genFnEpilog(BasicBlock* block)
370370
371371 bool jmpEpilog = block->HasFlag (BBF_HAS_JMP );
372372
373+ // BBF_HAS_JMP on wasm comes only from fast tail calls. The return_call already
374+ // left the function, but the body still needs an INS_end if this is the last block.
373375 if (jmpEpilog)
374376 {
375- NYI_WASM (" genFnEpilog: jmpEpilog" );
377+ if (block->IsLast () || m_compiler->bbIsFuncletBeg (block->Next ()))
378+ {
379+ instGen (INS_end);
380+ }
381+ return ;
376382 }
377383
378384 // TODO-WASM: shadow stack maintenance
@@ -2408,6 +2414,19 @@ void CodeGen::genCodeForPhysReg(GenTreePhysReg* tree)
24082414{
24092415 assert (genIsValidReg (tree->gtSrcReg ));
24102416 GetEmitter ()->emitIns_I (INS_local_get, emitActualTypeSize (tree), WasmRegToIndex (tree->gtSrcReg ));
2417+
2418+ if ((tree->gtLIRFlags & LIR ::Flags::WasmFastTailCallSp) != 0 )
2419+ {
2420+ // Fast tail call SP arg: undo the prolog SP adjustment (asserts funclet tail calls don't happen).
2421+ assert (m_compiler->funCurrentFuncIdx () == ROOT_FUNC_IDX );
2422+ assert (tree->gtSrcReg == GetStackPointerReg (m_compiler->funCurrentFuncIdx ()));
2423+ if (m_compiler->compLclFrameSize != 0 )
2424+ {
2425+ GetEmitter ()->emitIns_I (INS_I_const, EA_PTRSIZE , m_compiler->compLclFrameSize );
2426+ GetEmitter ()->emitIns (INS_I_add);
2427+ }
2428+ }
2429+
24112430 WasmProduceReg (tree);
24122431}
24132432
@@ -2571,7 +2590,33 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
25712590
25722591 ArrayStack<CorInfoWasmType> typeStack (m_compiler->getAllocator (CMK_Codegen));
25732592
2574- if (call->TypeIs (TYP_STRUCT ))
2593+ // For a fast tail call wasm requires the callee's result type to match the enclosing
2594+ // function's, so derive it from the caller's signature (call->gtType is TYP_VOID).
2595+ if (params.isJump )
2596+ {
2597+ if (m_compiler->info .compRetBuffArg != BAD_VAR_NUM )
2598+ {
2599+ // The enclosing method returns its struct via a retbuf arg, so the wasm-level
2600+ // return is empty.
2601+ typeStack.Push (CORINFO_WASM_TYPE_VOID );
2602+ }
2603+ else if (m_compiler->info .compRetType == TYP_VOID )
2604+ {
2605+ typeStack.Push (CORINFO_WASM_TYPE_VOID );
2606+ }
2607+ else if (m_compiler->info .compRetType == TYP_STRUCT )
2608+ {
2609+ typeStack.Push (
2610+ m_compiler->info .compCompHnd ->getWasmLowering (m_compiler->info .compMethodInfo ->args .retTypeClass ));
2611+ }
2612+ else
2613+ {
2614+ // Normalize small ints (bool/byte/short/...).
2615+ typeStack.Push ((CorInfoWasmType)emitter::GetWasmValueTypeCode (
2616+ ActualTypeToWasmValueType (m_compiler->info .compRetType )));
2617+ }
2618+ }
2619+ else if (call->TypeIs (TYP_STRUCT ))
25752620 {
25762621 typeStack.Push (m_compiler->info .compCompHnd ->getWasmLowering (call->gtRetClsHnd ));
25772622 }
0 commit comments