Explorar el Código

Allow `LocalVariable` to be assigned more than once (#2288)

* Allow `LocalVariable` to be assigned more than once

This allows us to write flow controls like loops and if-elses with
LocalVariables participating in phi nodes.

* Add `GetLocalNumber` to operand
FICTURE7 hace 4 años
padre
commit
c805542b29

+ 10 - 9
ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs

@@ -83,9 +83,10 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
             int intFreeRegisters = regMasks.IntAvailableRegisters;
             int intFreeRegisters = regMasks.IntAvailableRegisters;
             int vecFreeRegisters = regMasks.VecAvailableRegisters;
             int vecFreeRegisters = regMasks.VecAvailableRegisters;
 
 
-            BlockInfo[] blockInfo = new BlockInfo[cfg.Blocks.Count];
+            var blockInfo = new BlockInfo[cfg.Blocks.Count];
 
 
-            List<LocalInfo> locInfo = new List<LocalInfo>();
+            var locInfo = new List<LocalInfo>();
+            var locVisited = new HashSet<Operand>();
 
 
             for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--)
             for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--)
             {
             {
@@ -109,7 +110,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 
 
                         if (source.Kind == OperandKind.LocalVariable)
                         if (source.Kind == OperandKind.LocalVariable)
                         {
                         {
-                            locInfo[source.AsInt32() - 1].SetBlockIndex(block.Index);
+                            locInfo[source.GetLocalNumber() - 1].SetBlockIndex(block.Index);
                         }
                         }
                         else if (source.Kind == OperandKind.Memory)
                         else if (source.Kind == OperandKind.Memory)
                         {
                         {
@@ -117,12 +118,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 
 
                             if (memOp.BaseAddress != null)
                             if (memOp.BaseAddress != null)
                             {
                             {
-                                locInfo[memOp.BaseAddress.AsInt32() - 1].SetBlockIndex(block.Index);
+                                locInfo[memOp.BaseAddress.GetLocalNumber() - 1].SetBlockIndex(block.Index);
                             }
                             }
 
 
                             if (memOp.Index != null)
                             if (memOp.Index != null)
                             {
                             {
-                                locInfo[memOp.Index.AsInt32() - 1].SetBlockIndex(block.Index);
+                                locInfo[memOp.Index.GetLocalNumber() - 1].SetBlockIndex(block.Index);
                             }
                             }
                         }
                         }
                     }
                     }
@@ -135,9 +136,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
                         {
                         {
                             LocalInfo info;
                             LocalInfo info;
 
 
-                            if (dest.Value != 0)
+                            if (!locVisited.Add(dest))
                             {
                             {
-                                info = locInfo[dest.AsInt32() - 1];
+                                info = locInfo[dest.GetLocalNumber() - 1];
                             }
                             }
                             else
                             else
                             {
                             {
@@ -198,7 +199,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 
 
                     void AllocateRegister(Operand source, MemoryOperand memOp, int srcIndex)
                     void AllocateRegister(Operand source, MemoryOperand memOp, int srcIndex)
                     {
                     {
-                        LocalInfo info = locInfo[source.AsInt32() - 1];
+                        LocalInfo info = locInfo[source.GetLocalNumber() - 1];
 
 
                         info.UseCount++;
                         info.UseCount++;
 
 
@@ -317,7 +318,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
                             continue;
                             continue;
                         }
                         }
 
 
-                        LocalInfo info = locInfo[dest.AsInt32() - 1];
+                        LocalInfo info = locInfo[dest.GetLocalNumber() - 1];
 
 
                         if (info.UseCount == 0 && !info.PreAllocated)
                         if (info.UseCount == 0 && !info.PreAllocated)
                         {
                         {

+ 1 - 1
ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs

@@ -976,7 +976,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
         {
         {
             if (operand.Kind == OperandKind.LocalVariable)
             if (operand.Kind == OperandKind.LocalVariable)
             {
             {
-                return operand.AsInt32();
+                return operand.GetLocalNumber();
             }
             }
             else if (operand.Kind == OperandKind.Register)
             else if (operand.Kind == OperandKind.Register)
             {
             {

+ 8 - 0
ARMeilleure/IntermediateRepresentation/Operand.cs

@@ -1,5 +1,6 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.Runtime.CompilerServices;
 using System.Runtime.CompilerServices;
 
 
 namespace ARMeilleure.IntermediateRepresentation
 namespace ARMeilleure.IntermediateRepresentation
@@ -91,6 +92,13 @@ namespace ARMeilleure.IntermediateRepresentation
             return new Register((int)Value & 0xffffff, (RegisterType)(Value >> 24));
             return new Register((int)Value & 0xffffff, (RegisterType)(Value >> 24));
         }
         }
 
 
+        public int GetLocalNumber()
+        {
+            Debug.Assert(Kind == OperandKind.LocalVariable);
+
+            return (int)Value;
+        }
+
         public byte AsByte()
         public byte AsByte()
         {
         {
             return (byte)Value;
             return (byte)Value;

+ 3 - 1
ARMeilleure/Translation/ControlFlowGraph.cs

@@ -10,15 +10,17 @@ namespace ARMeilleure.Translation
         private BasicBlock[] _postOrderBlocks;
         private BasicBlock[] _postOrderBlocks;
         private int[] _postOrderMap;
         private int[] _postOrderMap;
 
 
+        public int LocalsCount { get; }
         public BasicBlock Entry { get; }
         public BasicBlock Entry { get; }
         public IntrusiveList<BasicBlock> Blocks { get; }
         public IntrusiveList<BasicBlock> Blocks { get; }
         public BasicBlock[] PostOrderBlocks => _postOrderBlocks;
         public BasicBlock[] PostOrderBlocks => _postOrderBlocks;
         public int[] PostOrderMap => _postOrderMap; 
         public int[] PostOrderMap => _postOrderMap; 
 
 
-        public ControlFlowGraph(BasicBlock entry, IntrusiveList<BasicBlock> blocks)
+        public ControlFlowGraph(BasicBlock entry, IntrusiveList<BasicBlock> blocks, int localsCount)
         {
         {
             Entry = entry;
             Entry = entry;
             Blocks = blocks;
             Blocks = blocks;
+            LocalsCount = localsCount;
 
 
             Update(removeUnreachableBlocks: true);
             Update(removeUnreachableBlocks: true);
         }
         }

+ 17 - 3
ARMeilleure/Translation/EmitterContext.cs

@@ -12,6 +12,8 @@ namespace ARMeilleure.Translation
 {
 {
     class EmitterContext
     class EmitterContext
     {
     {
+        private int _localsCount;
+
         private readonly Dictionary<Operand, BasicBlock> _irLabels;
         private readonly Dictionary<Operand, BasicBlock> _irLabels;
         private readonly IntrusiveList<BasicBlock> _irBlocks;
         private readonly IntrusiveList<BasicBlock> _irBlocks;
 
 
@@ -23,6 +25,8 @@ namespace ARMeilleure.Translation
 
 
         public EmitterContext()
         public EmitterContext()
         {
         {
+            _localsCount = 0;
+
             _irLabels = new Dictionary<Operand, BasicBlock>();
             _irLabels = new Dictionary<Operand, BasicBlock>();
             _irBlocks = new IntrusiveList<BasicBlock>();
             _irBlocks = new IntrusiveList<BasicBlock>();
 
 
@@ -30,6 +34,15 @@ namespace ARMeilleure.Translation
             _nextBlockFreq = BasicBlockFrequency.Default;
             _nextBlockFreq = BasicBlockFrequency.Default;
         }
         }
 
 
+        public Operand AllocateLocal(OperandType type)
+        {
+            Operand local = Local(type);
+
+            local.NumberLocal(++_localsCount);
+
+            return local;
+        }
+
         public Operand Add(Operand op1, Operand op2)
         public Operand Add(Operand op1, Operand op2)
         {
         {
             return Add(Instruction.Add, Local(op1.Type), op1, op2);
             return Add(Instruction.Add, Local(op1.Type), op1, op2);
@@ -223,9 +236,10 @@ namespace ARMeilleure.Translation
 
 
         public Operand Copy(Operand dest, Operand op1)
         public Operand Copy(Operand dest, Operand op1)
         {
         {
-            if (dest.Kind != OperandKind.Register)
+            if (dest.Kind != OperandKind.Register &&
+                (dest.Kind != OperandKind.LocalVariable || dest.GetLocalNumber() == 0))
             {
             {
-                throw new ArgumentException($"Invalid dest operand kind \"{dest.Kind}\".");
+                throw new ArgumentException($"Destination operand must be a Register or a numbered LocalVariable.");
             }
             }
 
 
             return Add(Instruction.Copy, dest, op1);
             return Add(Instruction.Copy, dest, op1);
@@ -670,7 +684,7 @@ namespace ARMeilleure.Translation
 
 
         public ControlFlowGraph GetControlFlowGraph()
         public ControlFlowGraph GetControlFlowGraph()
         {
         {
-            return new ControlFlowGraph(_irBlocks.First, _irBlocks);
+            return new ControlFlowGraph(_irBlocks.First, _irBlocks, _localsCount);
         }
         }
     }
     }
 }
 }

+ 8 - 2
ARMeilleure/Translation/SsaConstruction.cs

@@ -45,7 +45,7 @@ namespace ARMeilleure.Translation
         public static void Construct(ControlFlowGraph cfg)
         public static void Construct(ControlFlowGraph cfg)
         {
         {
             var globalDefs = new DefMap[cfg.Blocks.Count];
             var globalDefs = new DefMap[cfg.Blocks.Count];
-            var localDefs = new Operand[RegisterConsts.TotalCount];
+            var localDefs = new Operand[cfg.LocalsCount + RegisterConsts.TotalCount];
 
 
             var dfPhiBlocks = new Queue<BasicBlock>();
             var dfPhiBlocks = new Queue<BasicBlock>();
 
 
@@ -264,6 +264,12 @@ namespace ARMeilleure.Translation
 
 
                 return true;
                 return true;
             }
             }
+            else if (operand is { Kind: OperandKind.LocalVariable } && operand.GetLocalNumber() > 0)
+            {
+                result = RegisterConsts.TotalCount + operand.GetLocalNumber() - 1;
+
+                return true;
+            }
 
 
             result = -1;
             result = -1;
 
 
@@ -274,7 +280,7 @@ namespace ARMeilleure.Translation
         {
         {
             if (!TryGetId(operand, out int key))
             if (!TryGetId(operand, out int key))
             {
             {
-                Debug.Fail("OperandKind must be Register.");
+                Debug.Fail("OperandKind must be Register or a numbered LocalVariable.");
             }
             }
 
 
             return key;
             return key;