private void SplitAndSpillOverlappingIntervals(AllocationContext context, LiveInterval current) { foreach (int iIndex in context.Active) { LiveInterval interval = _intervals[iIndex]; if (!interval.IsFixed && interval.Register == current.Register) { SplitAndSpillOverlappingInterval(context, current, interval); context.Active.Clear(iIndex); } } foreach (int iIndex in context.Inactive) { LiveInterval interval = _intervals[iIndex]; if (!interval.IsFixed && interval.Register == current.Register && interval.Overlaps(current)) { SplitAndSpillOverlappingInterval(context, current, interval); context.Inactive.Clear(iIndex); } } }
private void AllocateInterval(AllocationContext context, LiveInterval current, int cIndex) { // Check active intervals that already ended. foreach (int iIndex in context.Active) { LiveInterval interval = _intervals[iIndex]; if (interval.GetEnd() < current.GetStart()) { context.Active.Clear(iIndex); } else if (!interval.Overlaps(current.GetStart())) { context.MoveActiveToInactive(iIndex); } } // Check inactive intervals that already ended or were reactivated. foreach (int iIndex in context.Inactive) { LiveInterval interval = _intervals[iIndex]; if (interval.GetEnd() < current.GetStart()) { context.Inactive.Clear(iIndex); } else if (interval.Overlaps(current.GetStart())) { context.MoveInactiveToActive(iIndex); } } if (!TryAllocateRegWithoutSpill(context, current, cIndex)) { AllocateRegWithSpill(context, current, cIndex); } }
private void AllocateRegWithSpill(AllocationContext context, LiveInterval current, int cIndex) { RegisterType regType = current.Local.Type.ToRegisterType(); int availableRegisters = context.Masks.GetAvailableRegisters(regType); int[] usePositions = new int[RegistersCount]; int[] blockedPositions = new int[RegistersCount]; for (int index = 0; index < RegistersCount; index++) { if ((availableRegisters & (1 << index)) != 0) { usePositions[index] = int.MaxValue; blockedPositions[index] = int.MaxValue; } } void SetUsePosition(int index, int position) { usePositions[index] = Math.Min(usePositions[index], position); } void SetBlockedPosition(int index, int position) { blockedPositions[index] = Math.Min(blockedPositions[index], position); SetUsePosition(index, position); } foreach (int iIndex in context.Active) { LiveInterval interval = _intervals[iIndex]; if (!interval.IsFixed && interval.Register.Type == regType) { int nextUse = interval.NextUseAfter(current.GetStart()); if (nextUse != -1) { SetUsePosition(interval.Register.Index, nextUse); } } } foreach (int iIndex in context.Inactive) { LiveInterval interval = _intervals[iIndex]; if (!interval.IsFixed && interval.Register.Type == regType && interval.Overlaps(current)) { int nextUse = interval.NextUseAfter(current.GetStart()); if (nextUse != -1) { SetUsePosition(interval.Register.Index, nextUse); } } } foreach (int iIndex in context.Active) { LiveInterval interval = _intervals[iIndex]; if (interval.IsFixed && interval.Register.Type == regType) { SetBlockedPosition(interval.Register.Index, 0); } } foreach (int iIndex in context.Inactive) { LiveInterval interval = _intervals[iIndex]; if (interval.IsFixed && interval.Register.Type == regType) { int overlapPosition = interval.GetOverlapPosition(current); if (overlapPosition != LiveInterval.NotFound) { SetBlockedPosition(interval.Register.Index, overlapPosition); } } } int selectedReg = GetHighestValueIndex(usePositions); int currentFirstUse = current.FirstUse(); Debug.Assert(currentFirstUse >= 0, "Current interval has no uses."); if (usePositions[selectedReg] < currentFirstUse) { // All intervals on inactive and active are being used before current, // so spill the current interval. Debug.Assert(currentFirstUse > current.GetStart(), "Trying to spill a interval currently being used."); LiveInterval splitChild = current.Split(currentFirstUse); Debug.Assert(splitChild.GetStart() > current.GetStart(), "Split interval has an invalid start position."); InsertInterval(splitChild); Spill(context, current); } else if (blockedPositions[selectedReg] > current.GetEnd()) { // Spill made the register available for the entire current lifetime, // so we only need to split the intervals using the selected register. current.Register = new Register(selectedReg, regType); SplitAndSpillOverlappingIntervals(context, current); context.Active.Set(cIndex); } else { // There are conflicts even after spill due to the use of fixed registers // that can't be spilled, so we need to also split current at the point of // the first fixed register use. current.Register = new Register(selectedReg, regType); int splitPosition = blockedPositions[selectedReg] & ~InstructionGapMask; Debug.Assert(splitPosition > current.GetStart(), "Trying to split a interval at a invalid position."); LiveInterval splitChild = current.Split(splitPosition); if (splitChild.UsesCount != 0) { Debug.Assert(splitChild.GetStart() > current.GetStart(), "Split interval has an invalid start position."); InsertInterval(splitChild); } else { Spill(context, splitChild); } SplitAndSpillOverlappingIntervals(context, current); context.Active.Set(cIndex); } }