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
This commit is contained in:
parent
212e472c9f
commit
c805542b29
6 changed files with 47 additions and 16 deletions
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Reference in a new issue