private void InsertSplitCopies() { Dictionary <int, CopyResolver> copyResolvers = new Dictionary <int, CopyResolver>(); CopyResolver GetCopyResolver(int position) { CopyResolver copyResolver = new CopyResolver(); if (copyResolvers.TryAdd(position, copyResolver)) { return(copyResolver); } return(copyResolvers[position]); } foreach (LiveInterval interval in _intervals.Where(x => x.IsSplit)) { LiveInterval previous = interval; foreach (LiveInterval splitChild in interval.SplitChilds()) { int splitPosition = splitChild.GetStart(); if (!_blockEdges.Contains(splitPosition) && previous.GetEnd() == splitPosition) { GetCopyResolver(splitPosition).AddSplit(previous, splitChild); } previous = splitChild; } } foreach (KeyValuePair <int, CopyResolver> kv in copyResolvers) { CopyResolver copyResolver = kv.Value; if (!copyResolver.HasCopy) { continue; } int splitPosition = kv.Key; LinkedListNode <Node> node = GetOperationNode(splitPosition); Operation[] sequence = copyResolver.Sequence(); node = node.List.AddBefore(node, sequence[0]); for (int index = 1; index < sequence.Length; index++) { node = node.List.AddAfter(node, sequence[index]); } } }
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); } }
private bool TryAllocateRegWithoutSpill(AllocationContext context, LiveInterval current, int cIndex) { RegisterType regType = current.Local.Type.ToRegisterType(); int availableRegisters = context.Masks.GetAvailableRegisters(regType); int[] freePositions = new int[RegistersCount]; for (int index = 0; index < RegistersCount; index++) { if ((availableRegisters & (1 << index)) != 0) { freePositions[index] = int.MaxValue; } } foreach (int iIndex in context.Active) { LiveInterval interval = _intervals[iIndex]; if (interval.Register.Type == regType) { freePositions[interval.Register.Index] = 0; } } foreach (int iIndex in context.Inactive) { LiveInterval interval = _intervals[iIndex]; if (interval.Register.Type == regType) { int overlapPosition = interval.GetOverlapPosition(current); if (overlapPosition != LiveInterval.NotFound && freePositions[interval.Register.Index] > overlapPosition) { freePositions[interval.Register.Index] = overlapPosition; } } } int selectedReg = GetHighestValueIndex(freePositions); int selectedNextUse = freePositions[selectedReg]; // Intervals starts and ends at odd positions, unless they span an entire // block, in this case they will have ranges at a even position. // When a interval is loaded from the stack to a register, we can only // do the split at a odd position, because otherwise the split interval // that is inserted on the list to be processed may clobber a register // used by the instruction at the same position as the split. // The problem only happens when a interval ends exactly at this instruction, // because otherwise they would interfere, and the register wouldn't be selected. // When the interval is aligned and the above happens, there's no problem as // the instruction that is actually with the last use is the one // before that position. selectedNextUse &= ~InstructionGapMask; if (selectedNextUse <= current.GetStart()) { return(false); } else if (selectedNextUse < current.GetEnd()) { Debug.Assert(selectedNextUse > current.GetStart(), "Trying to split interval at the start."); LiveInterval splitChild = current.Split(selectedNextUse); if (splitChild.UsesCount != 0) { Debug.Assert(splitChild.GetStart() > current.GetStart(), "Split interval has an invalid start position."); InsertInterval(splitChild); } else { Spill(context, splitChild); } } current.Register = new Register(selectedReg, regType); if (regType == RegisterType.Integer) { context.IntUsedRegisters |= 1 << selectedReg; } else /* if (regType == RegisterType.Vector) */ { context.VecUsedRegisters |= 1 << selectedReg; } context.Active.Set(cIndex); return(true); }