@@ -186,6 +186,7 @@ RefPosition* LinearScan::newRefPositionRaw(LsraLocation nodeLocation, GenTree* t
186
186
currBuildNode = nullptr ;
187
187
newRP->rpNum = static_cast <unsigned >(refPositions.size () - 1 );
188
188
#endif // DEBUG
189
+ recentRefPosition = newRP;
189
190
return newRP;
190
191
}
191
192
@@ -1141,8 +1142,9 @@ regMaskTP LinearScan::getKillSetForNode(GenTree* tree)
1141
1142
//
1142
1143
// Notes:
1143
1144
// The return value is needed because if we have any kills, we need to make sure that
1144
- // all defs are located AFTER the kills. On the other hand, if there aren't kills,
1145
- // the multiple defs for a regPair are in different locations.
1145
+ // all defs are located AFTER the kills. TODO: This is always the case.
1146
+ // On the other hand, if there aren't kills, the multiple defs for a regPair are in
1147
+ // different locations.
1146
1148
// If we generate any kills, we will mark all currentLiveVars as being preferenced
1147
1149
// to avoid the killed registers. This is somewhat conservative.
1148
1150
//
@@ -1167,6 +1169,18 @@ bool LinearScan::buildKillPositionsForNode(GenTree* tree, LsraLocation currentLo
1167
1169
// if (!blockSequence[curBBSeqNum]->isRunRarely())
1168
1170
if (enregisterLocalVars)
1169
1171
{
1172
+ const bool isCallKill = ((killMask == RBM_INT_CALLEE_TRASH) || (killMask == RBM_CALLEE_TRASH));
1173
+ if (isCallKill)
1174
+ {
1175
+ assert (recentRefPosition);
1176
+ if (recentRefPosition->refType != RefTypeBB)
1177
+ {
1178
+ callRefPositionLocations.push_back (recentRefPosition->nodeLocation );
1179
+ callKillMasks.push_back (killMask);
1180
+ callRefPositionCount++;
1181
+ }
1182
+ }
1183
+
1170
1184
VarSetOps::Iter iter (compiler, currentLiveVars);
1171
1185
unsigned varIndex = 0 ;
1172
1186
while (iter.NextElem (&varIndex))
@@ -1187,9 +1201,7 @@ bool LinearScan::buildKillPositionsForNode(GenTree* tree, LsraLocation currentLo
1187
1201
{
1188
1202
continue ;
1189
1203
}
1190
- Interval* interval = getIntervalForLocalVar (varIndex);
1191
- const bool isCallKill = ((killMask == RBM_INT_CALLEE_TRASH) || (killMask == RBM_CALLEE_TRASH));
1192
-
1204
+ Interval* interval = getIntervalForLocalVar (varIndex);
1193
1205
if (isCallKill)
1194
1206
{
1195
1207
interval->preferCalleeSave = true ;
@@ -2613,6 +2625,74 @@ void LinearScan::buildIntervals()
2613
2625
}
2614
2626
}
2615
2627
2628
+ // Adjust preferCalleeSave
2629
+ if (callRefPositionCount > 0 )
2630
+ {
2631
+ LsraLocation firstCallLocation = callRefPositionLocations.front ();
2632
+ LsraLocation lastCallLocation = callRefPositionLocations.back ();
2633
+
2634
+ JITDUMP (" \n\n CHECKING if Intervals can use callee-save registers" );
2635
+ JITDUMP (" \n ==============================\n " );
2636
+ for (Interval& interval : intervals)
2637
+ {
2638
+ if (interval.isLocalVar )
2639
+ {
2640
+ // We already handle them in BuildKillPositionsForNode.
2641
+ continue ;
2642
+ }
2643
+
2644
+ LsraLocation firstRef = interval.firstRefPosition ->nodeLocation ;
2645
+ LsraLocation lastRef = interval.lastRefPosition ->nodeLocation ;
2646
+
2647
+ if ((firstRef > lastCallLocation) || (lastRef < firstCallLocation))
2648
+ {
2649
+ // Current interval doesn't interfer with any calls. Skip it.
2650
+ continue ;
2651
+ }
2652
+
2653
+ jitstd::list<regMaskTP> callKillMasksLocal = callKillMasks;
2654
+ for (LsraLocation& callLocation : callRefPositionLocations)
2655
+ {
2656
+ regMaskTP killMask = callKillMasksLocal.front ();
2657
+ callKillMasksLocal.pop_front ();
2658
+
2659
+ if ((firstRef <= callLocation) && (callLocation < lastRef))
2660
+ {
2661
+ interval.preferCalleeSave = true ;
2662
+ if (!interval.isWriteThru )
2663
+ {
2664
+ // We are more conservative about allocating callee-saves registers to write-thru vars,
2665
+ // since a call only requires reloading after (not spilling before). So we record (above)
2666
+ // the fact that we'd prefer a callee-save register, but we don't update the preferences at
2667
+ // this point. See the "heuristics for writeThru intervals" in 'buildIntervals()'.
2668
+ regMaskTP newPreferences = allRegs (interval.registerType ) & ~killMask;
2669
+
2670
+ if (newPreferences != RBM_NONE)
2671
+ {
2672
+ if (VERBOSE)
2673
+ {
2674
+ printf (" Interval %2u: Update preferences (callee-save) from " ,
2675
+ interval.intervalIndex );
2676
+ dumpRegMask (interval.registerPreferences );
2677
+ printf (" to " );
2678
+ dumpRegMask (newPreferences);
2679
+ printf (" \n " );
2680
+ }
2681
+ interval.updateRegisterPreferences (newPreferences);
2682
+ }
2683
+ }
2684
+ break ;
2685
+ }
2686
+
2687
+ if (lastRef < callLocation)
2688
+ {
2689
+ // We passed lastRef, no point in checking further callRefPositions.
2690
+ break ;
2691
+ }
2692
+ }
2693
+ }
2694
+ }
2695
+
2616
2696
#ifdef DEBUG
2617
2697
if (getLsraExtendLifeTimes ())
2618
2698
{
0 commit comments