Explorar el Código

JIT: Coalesce copies on LSRA with simple register preferencing (#6950)

* JIT: Coalesce copies on LSRA with simple register preferencing

* PPTC version bump
gdkchan hace 1 año
padre
commit
0afa8f2c14

+ 34 - 5
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<int> span)
+        private static int GetHighestValueIndex(ReadOnlySpan<int> 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()]);
+                                }
+                            }
                         }
                     }
                 }

+ 21 - 0
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,25 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
             Register = register;
         }
 
+        public void SetCopySource(LiveInterval copySource)
+        {
+            CopySource = copySource;
+        }
+
+        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;

+ 1 - 1
src/ARMeilleure/Translation/PTC/Ptc.cs

@@ -29,7 +29,7 @@ namespace ARMeilleure.Translation.PTC
         private const string OuterHeaderMagicString = "PTCohd\0\0";
         private const string InnerHeaderMagicString = "PTCihd\0\0";
 
-        private const uint InternalVersion = 6634; //! To be incremented manually for each change to the ARMeilleure project.
+        private const uint InternalVersion = 6950; //! To be incremented manually for each change to the ARMeilleure project.
 
         private const string ActualDir = "0";
         private const string BackupDir = "1";