@@ -2897,12 +2897,77 @@ void* emitter::emitAddLabel(VARSET_VALARG_TP GCvars, regMaskTP gcrefRegs, regMas
28972897 }
28982898 else
28992899 {
2900- // other block kinds should emit something at the end that is not a call.
2900+ // other block kinds should emit something that is not a call at the end of the block .
29012901 assert (prevBlock->KindIs (BBJ_ALWAYS));
2902- // CONSIDER: We could patch up the previous call instruction with new GC info instead.
2903- // But that will need to be coordinated with how the GC info vor variables is used.
2904- // We currently apply that info to the instruction before the call. It may need to change.
2905- emitIns (INS_nop);
2902+
2903+ instrDesc* id = emitLastIns;
2904+ regMaskTP callGcrefRegs = gcrefRegs;
2905+ regMaskTP callByrefRegs = byrefRegs;
2906+
2907+ // We may see returns that become alive after the call,
2908+ // but those are tracked via idGCref/idSecondGCref. We do not need to track those in the call.
2909+ if (id->idGCref () == GCT_GCREF)
2910+ {
2911+ callGcrefRegs &= ~RBM_INTRET;
2912+ }
2913+ else if (id->idGCref () == GCT_BYREF)
2914+ {
2915+ callByrefRegs &= ~RBM_INTRET;
2916+ }
2917+
2918+ if (id->idIsLargeCall ())
2919+ {
2920+ instrDescCGCA* idCall = (instrDescCGCA*)id;
2921+ #if MULTIREG_HAS_SECOND_GC_RET
2922+ if (idCall->idSecondGCref () == GCT_GCREF)
2923+ {
2924+ callGcrefRegs &= ~RBM_INTRET_1;
2925+ }
2926+ else if (idCall->idSecondGCref () == GCT_BYREF)
2927+ {
2928+ callByrefRegs &= ~RBM_INTRET_1;
2929+ }
2930+ #endif // MULTIREG_HAS_SECOND_GC_RET
2931+
2932+ // new set must be a subset of old one
2933+ if ((idCall->idcGcrefRegs & callGcrefRegs) == callGcrefRegs &&
2934+ (idCall->idcByrefRegs & callByrefRegs) == callByrefRegs &&
2935+ VarSetOps::IsSubset (emitComp, GCvars, idCall->idcGCvars ))
2936+ {
2937+ // Update the liveness set.
2938+ VarSetOps::Assign (emitComp, idCall->idcGCvars , GCvars);
2939+ idCall->idcGcrefRegs = callGcrefRegs;
2940+ idCall->idcByrefRegs = callByrefRegs;
2941+ }
2942+ else
2943+ {
2944+ // I have never seen this triggered with large calls,
2945+ // but with small calls below it happens (although rarely)
2946+ assert (!" The live set is expanding!!!!" );
2947+
2948+ emitIns (INS_BREAKPOINT);
2949+ }
2950+ }
2951+ else
2952+ {
2953+ assert ((callGcrefRegs & RBM_CALLEE_TRASH) == 0 );
2954+
2955+ // new set must be a subset of old one
2956+ if ((emitDecodeCallGCregs (id) & callGcrefRegs) == callGcrefRegs && callByrefRegs == RBM_NONE &&
2957+ VarSetOps::IsEmpty (emitComp, GCvars))
2958+ {
2959+ // Update the liveness set.
2960+ emitEncodeCallGCregs (callGcrefRegs, id);
2961+ }
2962+ else
2963+ {
2964+ // The live set is expanding!!!!
2965+ // We branch here with live byref regs, which are not returns, and the call did not record any.
2966+ // Not sure why we see this, but it only can work if the label is unreachable from the call.
2967+ // Perhaps BBJ_ALWAYS somehow ended with a throwing call?
2968+ emitIns (INS_BREAKPOINT);
2969+ }
2970+ }
29062971 }
29072972 }
29082973 }
0 commit comments