@@ -2897,12 +2897,77 @@ void* emitter::emitAddLabel(VARSET_VALARG_TP GCvars, regMaskTP gcrefRegs, regMas
2897
2897
}
2898
2898
else
2899
2899
{
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 .
2901
2901
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
+ }
2906
2971
}
2907
2972
}
2908
2973
}
0 commit comments