From c805542b29975b0d9bf3ea324526f62cfe4331bf Mon Sep 17 00:00:00 2001 From: FICTURE7 Date: Mon, 17 May 2021 03:54:53 +0400 Subject: [PATCH] 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 --- .../RegisterAllocators/HybridAllocator.cs | 19 +++++++++--------- .../RegisterAllocators/LinearScanAllocator.cs | 2 +- .../IntermediateRepresentation/Operand.cs | 8 ++++++++ ARMeilleure/Translation/ControlFlowGraph.cs | 4 +++- ARMeilleure/Translation/EmitterContext.cs | 20 ++++++++++++++++--- ARMeilleure/Translation/SsaConstruction.cs | 10 ++++++++-- 6 files changed, 47 insertions(+), 16 deletions(-) diff --git a/ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs b/ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs index aa10aea07..2f68c43f8 100644 --- a/ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs +++ b/ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs @@ -83,9 +83,10 @@ namespace ARMeilleure.CodeGen.RegisterAllocators int intFreeRegisters = regMasks.IntAvailableRegisters; int vecFreeRegisters = regMasks.VecAvailableRegisters; - BlockInfo[] blockInfo = new BlockInfo[cfg.Blocks.Count]; + var blockInfo = new BlockInfo[cfg.Blocks.Count]; - List locInfo = new List(); + var locInfo = new List(); + var locVisited = new HashSet(); for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--) { @@ -109,7 +110,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators 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) { @@ -117,12 +118,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators if (memOp.BaseAddress != null) { - locInfo[memOp.BaseAddress.AsInt32() - 1].SetBlockIndex(block.Index); + locInfo[memOp.BaseAddress.GetLocalNumber() - 1].SetBlockIndex(block.Index); } 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; - if (dest.Value != 0) + if (!locVisited.Add(dest)) { - info = locInfo[dest.AsInt32() - 1]; + info = locInfo[dest.GetLocalNumber() - 1]; } else { @@ -198,7 +199,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators void AllocateRegister(Operand source, MemoryOperand memOp, int srcIndex) { - LocalInfo info = locInfo[source.AsInt32() - 1]; + LocalInfo info = locInfo[source.GetLocalNumber() - 1]; info.UseCount++; @@ -317,7 +318,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators continue; } - LocalInfo info = locInfo[dest.AsInt32() - 1]; + LocalInfo info = locInfo[dest.GetLocalNumber() - 1]; if (info.UseCount == 0 && !info.PreAllocated) { diff --git a/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs b/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs index cd36bdc02..88adeeb0f 100644 --- a/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs +++ b/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs @@ -976,7 +976,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators { if (operand.Kind == OperandKind.LocalVariable) { - return operand.AsInt32(); + return operand.GetLocalNumber(); } else if (operand.Kind == OperandKind.Register) { diff --git a/ARMeilleure/IntermediateRepresentation/Operand.cs b/ARMeilleure/IntermediateRepresentation/Operand.cs index 7b486c55d..ec0239392 100644 --- a/ARMeilleure/IntermediateRepresentation/Operand.cs +++ b/ARMeilleure/IntermediateRepresentation/Operand.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Runtime.CompilerServices; namespace ARMeilleure.IntermediateRepresentation @@ -91,6 +92,13 @@ namespace ARMeilleure.IntermediateRepresentation return new Register((int)Value & 0xffffff, (RegisterType)(Value >> 24)); } + public int GetLocalNumber() + { + Debug.Assert(Kind == OperandKind.LocalVariable); + + return (int)Value; + } + public byte AsByte() { return (byte)Value; diff --git a/ARMeilleure/Translation/ControlFlowGraph.cs b/ARMeilleure/Translation/ControlFlowGraph.cs index ee1a245e0..4c76d5dd1 100644 --- a/ARMeilleure/Translation/ControlFlowGraph.cs +++ b/ARMeilleure/Translation/ControlFlowGraph.cs @@ -10,15 +10,17 @@ namespace ARMeilleure.Translation private BasicBlock[] _postOrderBlocks; private int[] _postOrderMap; + public int LocalsCount { get; } public BasicBlock Entry { get; } public IntrusiveList Blocks { get; } public BasicBlock[] PostOrderBlocks => _postOrderBlocks; public int[] PostOrderMap => _postOrderMap; - public ControlFlowGraph(BasicBlock entry, IntrusiveList blocks) + public ControlFlowGraph(BasicBlock entry, IntrusiveList blocks, int localsCount) { Entry = entry; Blocks = blocks; + LocalsCount = localsCount; Update(removeUnreachableBlocks: true); } diff --git a/ARMeilleure/Translation/EmitterContext.cs b/ARMeilleure/Translation/EmitterContext.cs index 5c608b3d3..cc2205cec 100644 --- a/ARMeilleure/Translation/EmitterContext.cs +++ b/ARMeilleure/Translation/EmitterContext.cs @@ -12,6 +12,8 @@ namespace ARMeilleure.Translation { class EmitterContext { + private int _localsCount; + private readonly Dictionary _irLabels; private readonly IntrusiveList _irBlocks; @@ -23,6 +25,8 @@ namespace ARMeilleure.Translation public EmitterContext() { + _localsCount = 0; + _irLabels = new Dictionary(); _irBlocks = new IntrusiveList(); @@ -30,6 +34,15 @@ namespace ARMeilleure.Translation _nextBlockFreq = BasicBlockFrequency.Default; } + public Operand AllocateLocal(OperandType type) + { + Operand local = Local(type); + + local.NumberLocal(++_localsCount); + + return local; + } + public Operand Add(Operand op1, Operand op2) { return Add(Instruction.Add, Local(op1.Type), op1, op2); @@ -223,9 +236,10 @@ namespace ARMeilleure.Translation 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); @@ -670,7 +684,7 @@ namespace ARMeilleure.Translation public ControlFlowGraph GetControlFlowGraph() { - return new ControlFlowGraph(_irBlocks.First, _irBlocks); + return new ControlFlowGraph(_irBlocks.First, _irBlocks, _localsCount); } } } diff --git a/ARMeilleure/Translation/SsaConstruction.cs b/ARMeilleure/Translation/SsaConstruction.cs index 1c6e83c9c..76cb9a442 100644 --- a/ARMeilleure/Translation/SsaConstruction.cs +++ b/ARMeilleure/Translation/SsaConstruction.cs @@ -45,7 +45,7 @@ namespace ARMeilleure.Translation public static void Construct(ControlFlowGraph cfg) { 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(); @@ -264,6 +264,12 @@ namespace ARMeilleure.Translation return true; } + else if (operand is { Kind: OperandKind.LocalVariable } && operand.GetLocalNumber() > 0) + { + result = RegisterConsts.TotalCount + operand.GetLocalNumber() - 1; + + return true; + } result = -1; @@ -274,7 +280,7 @@ namespace ARMeilleure.Translation { if (!TryGetId(operand, out int key)) { - Debug.Fail("OperandKind must be Register."); + Debug.Fail("OperandKind must be Register or a numbered LocalVariable."); } return key;