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:
FICTURE7 2021-05-17 03:54:53 +04:00 committed by GitHub
parent 212e472c9f
commit c805542b29
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 47 additions and 16 deletions

View file

@ -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)
{ {

View file

@ -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)
{ {

View file

@ -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;

View file

@ -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);
} }

View file

@ -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);
} }
} }
} }

View file

@ -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;