@@ -504,7 +504,10 @@ void CodeGenInterface::genUpdateRegLife(const LclVarDsc* varDsc, bool isBorn, bo
504504 }
505505 else
506506 {
507- assert ((regSet.GetMaskVars () & regMask) == 0 );
507+ // If this is going live, the register must not have a variable in it, except
508+ // in the case of an exception variable, which may be already treated as live
509+ // in the register.
510+ assert (varDsc->lvLiveInOutOfHndlr || ((regSet.GetMaskVars () & regMask) == 0 ));
508511 regSet.AddMaskVars (regMask);
509512 }
510513}
@@ -681,12 +684,14 @@ void Compiler::compChangeLife(VARSET_VALARG_TP newLife)
681684 unsigned deadVarIndex = 0 ;
682685 while (deadIter.NextElem (&deadVarIndex))
683686 {
684- unsigned varNum = lvaTrackedIndexToLclNum (deadVarIndex);
685- LclVarDsc* varDsc = lvaGetDesc (varNum);
686- bool isGCRef = (varDsc->TypeGet () == TYP_REF);
687- bool isByRef = (varDsc->TypeGet () == TYP_BYREF);
687+ unsigned varNum = lvaTrackedIndexToLclNum (deadVarIndex);
688+ LclVarDsc* varDsc = lvaGetDesc (varNum);
689+ bool isGCRef = (varDsc->TypeGet () == TYP_REF);
690+ bool isByRef = (varDsc->TypeGet () == TYP_BYREF);
691+ bool isInReg = varDsc->lvIsInReg ();
692+ bool isInMemory = !isInReg || varDsc->lvLiveInOutOfHndlr ;
688693
689- if (varDsc-> lvIsInReg () )
694+ if (isInReg )
690695 {
691696 // TODO-Cleanup: Move the code from compUpdateLifeVar to genUpdateRegLife that updates the
692697 // gc sets
@@ -701,8 +706,8 @@ void Compiler::compChangeLife(VARSET_VALARG_TP newLife)
701706 }
702707 codeGen->genUpdateRegLife (varDsc, false /* isBorn*/ , true /* isDying*/ DEBUGARG (nullptr ));
703708 }
704- // This isn't in a register, so update the gcVarPtrSetCur .
705- else if (isGCRef || isByRef)
709+ // Update the gcVarPtrSetCur if it is in memory .
710+ if (isInMemory && ( isGCRef || isByRef) )
706711 {
707712 VarSetOps::RemoveElemD (this , codeGen->gcInfo .gcVarPtrSetCur , deadVarIndex);
708713 JITDUMP (" \t\t\t\t\t\t\t V%02u becoming dead\n " , varNum);
@@ -724,13 +729,18 @@ void Compiler::compChangeLife(VARSET_VALARG_TP newLife)
724729
725730 if (varDsc->lvIsInReg ())
726731 {
727- #ifdef DEBUG
728- if (VarSetOps::IsMember (this , codeGen->gcInfo .gcVarPtrSetCur , bornVarIndex))
732+ // If this variable is going live in a register, it is no longer live on the stack,
733+ // unless it is an EH var, which always remains live on the stack.
734+ if (!varDsc->lvLiveInOutOfHndlr )
729735 {
730- JITDUMP (" \t\t\t\t\t\t\t Removing V%02u from gcVarPtrSetCur\n " , varNum);
731- }
736+ #ifdef DEBUG
737+ if (VarSetOps::IsMember (this , codeGen->gcInfo .gcVarPtrSetCur , bornVarIndex))
738+ {
739+ JITDUMP (" \t\t\t\t\t\t\t Removing V%02u from gcVarPtrSetCur\n " , varNum);
740+ }
732741#endif // DEBUG
733- VarSetOps::RemoveElemD (this , codeGen->gcInfo .gcVarPtrSetCur , bornVarIndex);
742+ VarSetOps::RemoveElemD (this , codeGen->gcInfo .gcVarPtrSetCur , bornVarIndex);
743+ }
734744 codeGen->genUpdateRegLife (varDsc, true /* isBorn*/ , false /* isDying*/ DEBUGARG (nullptr ));
735745 regMaskTP regMask = varDsc->lvRegMask ();
736746 if (isGCRef)
@@ -742,9 +752,9 @@ void Compiler::compChangeLife(VARSET_VALARG_TP newLife)
742752 codeGen->gcInfo .gcRegByrefSetCur |= regMask;
743753 }
744754 }
745- // This isn't in a register, so update the gcVarPtrSetCur
746755 else if (lvaIsGCTracked (varDsc))
747756 {
757+ // This isn't in a register, so update the gcVarPtrSetCur to show that it's live on the stack.
748758 VarSetOps::AddElemD (this , codeGen->gcInfo .gcVarPtrSetCur , bornVarIndex);
749759 JITDUMP (" \t\t\t\t\t\t\t V%02u becoming live\n " , varNum);
750760 }
@@ -3269,6 +3279,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
32693279 // 1 means the first part of a register argument
32703280 // 2, 3 or 4 means the second,third or fourth part of a multireg argument
32713281 bool stackArg; // true if the argument gets homed to the stack
3282+ bool writeThru; // true if the argument gets homed to both stack and register
32723283 bool processed; // true after we've processed the argument (and it is in its final location)
32733284 bool circular; // true if this register participates in a circular dependency loop.
32743285
@@ -3605,6 +3616,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
36053616 }
36063617
36073618 regArgTab[regArgNum + i].processed = false ;
3619+ regArgTab[regArgNum + i].writeThru = (varDsc->lvIsInReg () && varDsc->lvLiveInOutOfHndlr );
36083620
36093621 /* mark stack arguments since we will take care of those first */
36103622 regArgTab[regArgNum + i].stackArg = (varDsc->lvIsInReg ()) ? false : true ;
@@ -3765,9 +3777,9 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
37653777 noway_assert (((regArgMaskLive & RBM_FLTARG_REGS) == 0 ) &&
37663778 " Homing of float argument registers with circular dependencies not implemented." );
37673779
3768- /* Now move the arguments to their locations.
3769- * First consider ones that go on the stack since they may
3770- * free some registers. */
3780+ // Now move the arguments to their locations.
3781+ // First consider ones that go on the stack since they may free some registers.
3782+ // Also home writeThru args, since they're also homed to the stack.
37713783
37723784 regArgMaskLive = regState->rsCalleeRegArgMaskLiveIn ; // reset the live in to what it was at the start
37733785 for (argNum = 0 ; argNum < argMax; argNum++)
@@ -3805,7 +3817,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
38053817 // If this arg is never on the stack, go to the next one.
38063818 if (varDsc->lvType == TYP_LONG)
38073819 {
3808- if (regArgTab[argNum].slot == 1 && !regArgTab[argNum].stackArg )
3820+ if (regArgTab[argNum].slot == 1 && !regArgTab[argNum].stackArg && !regArgTab[argNum]. writeThru )
38093821 {
38103822 continue ;
38113823 }
@@ -3839,7 +3851,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
38393851
38403852 noway_assert (varDsc->lvIsParam );
38413853 noway_assert (varDsc->lvIsRegArg );
3842- noway_assert (varDsc->lvIsInReg () == false ||
3854+ noway_assert (varDsc->lvIsInReg () == false || varDsc-> lvLiveInOutOfHndlr ||
38433855 (varDsc->lvType == TYP_LONG && varDsc->GetOtherReg () == REG_STK && regArgTab[argNum].slot == 2 ));
38443856
38453857 var_types storeType = TYP_UNDEF;
@@ -3906,13 +3918,17 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
39063918#endif // USING_SCOPE_INFO
39073919 }
39083920
3909- /* mark the argument as processed */
3910-
3911- regArgTab[argNum].processed = true ;
3912- regArgMaskLive &= ~genRegMask (srcRegNum);
3921+ // Mark the argument as processed, and set it as no longer live in srcRegNum,
3922+ // unless it is a writeThru var, in which case we home it to the stack, but
3923+ // don't mark it as processed until below.
3924+ if (!regArgTab[argNum].writeThru )
3925+ {
3926+ regArgTab[argNum].processed = true ;
3927+ regArgMaskLive &= ~genRegMask (srcRegNum);
3928+ }
39133929
39143930#if defined(TARGET_ARM)
3915- if (storeType == TYP_DOUBLE)
3931+ if (( storeType == TYP_DOUBLE) && !regArgTab[argNum]. writeThru )
39163932 {
39173933 regArgTab[argNum + 1 ].processed = true ;
39183934 regArgMaskLive &= ~genRegMask (REG_NEXT(srcRegNum));
@@ -4618,7 +4634,7 @@ void CodeGen::genCheckUseBlockInit()
46184634 {
46194635 if (!varDsc->lvRegister )
46204636 {
4621- if (!varDsc->lvIsInReg ())
4637+ if (!varDsc->lvIsInReg () || varDsc-> lvLiveInOutOfHndlr )
46224638 {
46234639 // Var is on the stack at entry.
46244640 initStkLclCnt +=
@@ -7233,7 +7249,9 @@ void CodeGen::genFnProlog()
72337249 continue ;
72347250 }
72357251
7236- if (varDsc->lvIsInReg ())
7252+ bool isInReg = varDsc->lvIsInReg ();
7253+ bool isInMemory = !isInReg || varDsc->lvLiveInOutOfHndlr ;
7254+ if (isInReg)
72377255 {
72387256 regMaskTP regMask = genRegMask (varDsc->GetRegNum ());
72397257 if (!varDsc->IsFloatRegType ())
@@ -7264,7 +7282,7 @@ void CodeGen::genFnProlog()
72647282 initFltRegs |= regMask;
72657283 }
72667284 }
7267- else
7285+ if (isInMemory)
72687286 {
72697287 INIT_STK:
72707288
0 commit comments