@@ -2675,54 +2675,76 @@ void CodeGen::genJmpMethod(GenTree* jmp)
26752675 if (varDsc->lvRegNum != argReg)
26762676 {
26772677 var_types loadType = TYP_UNDEF;
2678- if (varTypeIsStruct (varDsc))
2679- {
2680- // Must be <= 16 bytes or else it wouldn't be passed in registers
2681- noway_assert (EA_SIZE_IN_BYTES (varDsc->lvSize ()) <= MAX_PASS_MULTIREG_BYTES);
2682- loadType = compiler->getJitGCType (varDsc->lvGcLayout [0 ]);
2683- }
2684- else
2678+
2679+ if (varDsc->lvIsHfaRegArg ())
26852680 {
2686- loadType = compiler-> mangleVarArgsType ( genActualType (varDsc-> TypeGet ()));
2687- }
2688- emitAttr loadSize = emitActualTypeSize (loadType);
2689- getEmitter ()-> emitIns_R_S ( ins_Load (loadType), loadSize, argReg, varNum, 0 );
2681+ // Note that for HFA, the argument is currently marked address exposed so lvRegNum will always be
2682+ // REG_STK. We home the incoming HFA argument registers in the prolog. Then we'll load them back
2683+ // here, whether they are already in the correct registers or not. This is such a corner case that
2684+ // it is not worth optimizing it.
26902685
2691- // Update argReg life and GC Info to indicate varDsc stack slot is dead and argReg is going live.
2692- // Note that we cannot modify varDsc->lvRegNum here because another basic block may not be expecting it.
2693- // Therefore manually update life of argReg. Note that GT_JMP marks the end of the basic block
2694- // and after which reg life and gc info will be recomputed for the new block in genCodeForBBList().
2695- regSet.AddMaskVars (genRegMask (argReg));
2696- gcInfo.gcMarkRegPtrVal (argReg, loadType);
2686+ assert (!compiler->info .compIsVarArgs );
26972687
2698- if (compiler->lvaIsMultiregStruct (varDsc, compiler->info .compIsVarArgs ))
2688+ loadType = varDsc->GetHfaType ();
2689+ regNumber fieldReg = argReg;
2690+ emitAttr loadSize = emitActualTypeSize (loadType);
2691+ unsigned cSlots = varDsc->lvHfaSlots ();
2692+
2693+ for (unsigned ofs = 0 , cSlot = 0 ; cSlot < cSlots; cSlot++, ofs += (unsigned )loadSize)
2694+ {
2695+ getEmitter ()->emitIns_R_S (ins_Load (loadType), loadSize, fieldReg, varNum, ofs);
2696+ assert (genIsValidFloatReg (fieldReg)); // No GC register tracking for floating point registers.
2697+ fieldReg = regNextOfType (fieldReg, loadType);
2698+ }
2699+ }
2700+ else
26992701 {
2700- if (varDsc->lvIsHfa ())
2702+ if (varTypeIsStruct (varDsc))
2703+ {
2704+ // Must be <= 16 bytes or else it wouldn't be passed in registers, except for HFA,
2705+ // which can be bigger (and is handled above).
2706+ noway_assert (EA_SIZE_IN_BYTES (varDsc->lvSize ()) <= 16 );
2707+ loadType = compiler->getJitGCType (varDsc->lvGcLayout [0 ]);
2708+ }
2709+ else
27012710 {
2702- NYI_ARM64 ( " CodeGen::genJmpMethod with multireg HFA arg " );
2711+ loadType = compiler-> mangleVarArgsType ( genActualType (varDsc-> TypeGet ()) );
27032712 }
2713+ emitAttr loadSize = emitActualTypeSize (loadType);
2714+ getEmitter ()->emitIns_R_S (ins_Load (loadType), loadSize, argReg, varNum, 0 );
2715+
2716+ // Update argReg life and GC Info to indicate varDsc stack slot is dead and argReg is going live.
2717+ // Note that we cannot modify varDsc->lvRegNum here because another basic block may not be expecting it.
2718+ // Therefore manually update life of argReg. Note that GT_JMP marks the end of the basic block
2719+ // and after which reg life and gc info will be recomputed for the new block in genCodeForBBList().
2720+ regSet.AddMaskVars (genRegMask (argReg));
2721+ gcInfo.gcMarkRegPtrVal (argReg, loadType);
27042722
2705- // Restore the second register.
2706- argRegNext = genRegArgNext (argReg);
2723+ if (compiler->lvaIsMultiregStruct (varDsc, compiler->info .compIsVarArgs ))
2724+ {
2725+ // Restore the second register.
2726+ argRegNext = genRegArgNext (argReg);
27072727
2708- loadType = compiler->getJitGCType (varDsc->lvGcLayout [1 ]);
2709- loadSize = emitActualTypeSize (loadType);
2710- getEmitter ()->emitIns_R_S (ins_Load (loadType), loadSize, argRegNext, varNum, TARGET_POINTER_SIZE);
2728+ loadType = compiler->getJitGCType (varDsc->lvGcLayout [1 ]);
2729+ loadSize = emitActualTypeSize (loadType);
2730+ getEmitter ()->emitIns_R_S (ins_Load (loadType), loadSize, argRegNext, varNum, TARGET_POINTER_SIZE);
27112731
2712- regSet.AddMaskVars (genRegMask (argRegNext));
2713- gcInfo.gcMarkRegPtrVal (argRegNext, loadType);
2714- }
2732+ regSet.AddMaskVars (genRegMask (argRegNext));
2733+ gcInfo.gcMarkRegPtrVal (argRegNext, loadType);
2734+ }
27152735
2716- if (compiler->lvaIsGCTracked (varDsc))
2717- {
2718- VarSetOps::RemoveElemD (compiler, gcInfo.gcVarPtrSetCur , varDsc->lvVarIndex );
2736+ if (compiler->lvaIsGCTracked (varDsc))
2737+ {
2738+ VarSetOps::RemoveElemD (compiler, gcInfo.gcVarPtrSetCur , varDsc->lvVarIndex );
2739+ }
27192740 }
27202741 }
27212742
27222743 if (compiler->info .compIsVarArgs )
27232744 {
27242745 // In case of a jmp call to a vararg method ensure only integer registers are passed.
27252746 assert ((genRegMask (argReg) & (RBM_ARG_REGS | RBM_ARG_RET_BUFF)) != RBM_NONE);
2747+ assert (!varDsc->lvIsHfaRegArg ());
27262748
27272749 fixedIntArgMask |= genRegMask (argReg);
27282750
0 commit comments