From 8a38a6a87c7b3e3e7638405ffcb57a899064d40b Mon Sep 17 00:00:00 2001 From: Gabriel A Date: Sun, 16 Jun 2024 21:26:49 -0300 Subject: [PATCH] JIT: Coalesce copies on LSRA with simple register preferencing --- .../RegisterAllocators/LinearScanAllocator.cs | 39 ++++++++++++++++--- .../RegisterAllocators/LiveInterval.cs | 35 +++++++++++++++++ 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/src/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs b/src/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs index f156e0886b..16feeb914b 100644 --- a/src/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs +++ b/src/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs @@ -251,7 +251,20 @@ namespace ARMeilleure.CodeGen.RegisterAllocators } } - int selectedReg = GetHighestValueIndex(freePositions); + // If this is a copy destination variable, we prefer the register used for the copy source. + // If the register is available, then the copy can be eliminated later as both source + // and destination will use the same register. + int selectedReg; + + if (current.TryGetCopySourceRegister(out int preferredReg) && freePositions[preferredReg] >= current.GetEnd()) + { + selectedReg = preferredReg; + } + else + { + selectedReg = GetHighestValueIndex(freePositions); + } + int selectedNextUse = freePositions[selectedReg]; // Intervals starts and ends at odd positions, unless they span an entire @@ -431,7 +444,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators } } - private static int GetHighestValueIndex(Span span) + private static int GetHighestValueIndex(ReadOnlySpan span) { int highest = int.MinValue; @@ -798,12 +811,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators // The "visited" state is stored in the MSB of the local's value. const ulong VisitedMask = 1ul << 63; - bool IsVisited(Operand local) + static bool IsVisited(Operand local) { return (local.GetValueUnsafe() & VisitedMask) != 0; } - void SetVisited(Operand local) + static void SetVisited(Operand local) { local.GetValueUnsafe() |= VisitedMask; } @@ -826,9 +839,25 @@ namespace ARMeilleure.CodeGen.RegisterAllocators { dest.NumberLocal(_intervals.Count); - _intervals.Add(new LiveInterval(dest)); + LiveInterval interval = new LiveInterval(dest); + _intervals.Add(interval); SetVisited(dest); + + // If this is a copy (or copy-like operation), set the copy source interval as well. + // This is used for register preferencing later on, which allows the copy to be eliminated + // in some cases. + if (node.Instruction == Instruction.Copy || node.Instruction == Instruction.ZeroExtend32) + { + Operand source = node.GetSource(0); + + if (source.Kind == OperandKind.LocalVariable && + source.GetLocalNumber() > 0 && + (node.Instruction == Instruction.Copy || source.Type == OperandType.I32)) + { + interval.SetCopySource(_intervals[source.GetLocalNumber()]); + } + } } } } diff --git a/src/ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs b/src/ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs index 333d3951b1..fe8d78ac50 100644 --- a/src/ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs +++ b/src/ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs @@ -19,6 +19,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators public LiveRange CurrRange; public LiveInterval Parent; + public LiveInterval CopySource; public UseList Uses; public LiveIntervalList Children; @@ -37,6 +38,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators private ref LiveRange CurrRange => ref _data->CurrRange; private ref LiveRange PrevRange => ref _data->PrevRange; private ref LiveInterval Parent => ref _data->Parent; + private ref LiveInterval CopySource => ref _data->CopySource; private ref UseList Uses => ref _data->Uses; private ref LiveIntervalList Children => ref _data->Children; @@ -78,6 +80,39 @@ namespace ARMeilleure.CodeGen.RegisterAllocators Register = register; } + public void SetCopySource(LiveInterval copySource) + { + CopySource = copySource; + } + + public bool TryGetCopySource(out LiveInterval copySource) + { + if (CopySource._data != null) + { + copySource = CopySource; + + return true; + } + + copySource = default; + + return false; + } + + public bool TryGetCopySourceRegister(out int copySourceRegIndex) + { + if (CopySource._data != null) + { + copySourceRegIndex = CopySource.Register.Index; + + return true; + } + + copySourceRegIndex = 0; + + return false; + } + public void Reset() { PrevRange = default;