Reduce allocation during SSA construction (#2162)

* Reduce allocation during SSA construction

* Re-trigger CI
This commit is contained in:
FICTURE7 2021-04-02 21:26:16 +04:00 committed by GitHub
parent 529df341f1
commit 8b3eba7e13
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 111 additions and 127 deletions

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace ARMeilleure.IntermediateRepresentation namespace ARMeilleure.IntermediateRepresentation
{ {
@ -84,6 +85,7 @@ namespace ARMeilleure.IntermediateRepresentation
return With(OperandKind.Register, type, (ulong)((int)regType << 24 | index)); return With(OperandKind.Register, type, (ulong)((int)regType << 24 | index));
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Register GetRegister() public Register GetRegister()
{ {
return new Register((int)Value & 0xffffff, (RegisterType)(Value >> 24)); return new Register((int)Value & 0xffffff, (RegisterType)(Value >> 24));

View file

@ -1,8 +1,9 @@
using ARMeilleure.Common; using ARMeilleure.Common;
using ARMeilleure.IntermediateRepresentation; using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State; using ARMeilleure.State;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using static ARMeilleure.IntermediateRepresentation.OperandHelper; using static ARMeilleure.IntermediateRepresentation.OperandHelper;
namespace ARMeilleure.Translation namespace ARMeilleure.Translation
@ -11,104 +12,92 @@ namespace ARMeilleure.Translation
{ {
private class DefMap private class DefMap
{ {
private Dictionary<Register, Operand> _map; private readonly Dictionary<int, Operand> _map;
private readonly BitMap _phiMasks;
private BitMap _phiMasks;
public DefMap() public DefMap()
{ {
_map = new Dictionary<Register, Operand>(); _map = new Dictionary<int, Operand>();
_phiMasks = new BitMap(RegisterConsts.TotalCount); _phiMasks = new BitMap(RegisterConsts.TotalCount);
} }
public bool TryAddOperand(Register reg, Operand operand) public bool TryAddOperand(int key, Operand operand)
{ {
return _map.TryAdd(reg, operand); return _map.TryAdd(key, operand);
} }
public bool TryGetOperand(Register reg, out Operand operand) public bool TryGetOperand(int key, out Operand operand)
{ {
return _map.TryGetValue(reg, out operand); return _map.TryGetValue(key, out operand);
} }
public bool AddPhi(Register reg) public bool AddPhi(int key)
{ {
return _phiMasks.Set(GetIdFromRegister(reg)); return _phiMasks.Set(key);
} }
public bool HasPhi(Register reg) public bool HasPhi(int key)
{ {
return _phiMasks.IsSet(GetIdFromRegister(reg)); return _phiMasks.IsSet(key);
} }
} }
public static void Construct(ControlFlowGraph cfg) public static void Construct(ControlFlowGraph cfg)
{ {
DefMap[] globalDefs = new DefMap[cfg.Blocks.Count]; var globalDefs = new DefMap[cfg.Blocks.Count];
var localDefs = new Operand[RegisterConsts.TotalCount];
var dfPhiBlocks = new Queue<BasicBlock>();
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
{ {
globalDefs[block.Index] = new DefMap(); globalDefs[block.Index] = new DefMap();
} }
Queue<BasicBlock> dfPhiBlocks = new Queue<BasicBlock>();
// First pass, get all defs and locals uses. // First pass, get all defs and locals uses.
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
{ {
Operand[] localDefs = new Operand[RegisterConsts.TotalCount]; for (Node node = block.Operations.First; node != null; node = node.ListNext)
Node node = block.Operations.First;
Operand RenameLocal(Operand operand)
{ {
if (operand != null && operand.Kind == OperandKind.Register) if (node is not Operation operation)
{ {
Operand local = localDefs[GetIdFromRegister(operand.GetRegister())]; continue;
operand = local ?? operand;
} }
return operand;
}
while (node != null)
{
if (node is Operation operation)
{
for (int index = 0; index < operation.SourcesCount; index++) for (int index = 0; index < operation.SourcesCount; index++)
{ {
operation.SetSource(index, RenameLocal(operation.GetSource(index))); Operand src = operation.GetSource(index);
if (TryGetId(src, out int srcKey))
{
Operand local = localDefs[srcKey] ?? src;
operation.SetSource(index, local);
}
} }
Operand dest = operation.Destination; Operand dest = operation.Destination;
if (dest != null && dest.Kind == OperandKind.Register) if (TryGetId(dest, out int destKey))
{ {
Operand local = Local(dest.Type); Operand local = Local(dest.Type);
localDefs[GetIdFromRegister(dest.GetRegister())] = local; localDefs[destKey] = local;
operation.Destination = local; operation.Destination = local;
} }
} }
node = node.ListNext; for (int key = 0; key < localDefs.Length; key++)
}
for (int index = 0; index < RegisterConsts.TotalCount; index++)
{ {
Operand local = localDefs[index]; Operand local = localDefs[key];
if (local == null) if (local is null)
{ {
continue; continue;
} }
Register reg = GetRegisterFromId(index); globalDefs[block.Index].TryAddOperand(key, local);
globalDefs[block.Index].TryAddOperand(reg, local);
dfPhiBlocks.Enqueue(block); dfPhiBlocks.Enqueue(block);
@ -116,61 +105,53 @@ namespace ARMeilleure.Translation
{ {
foreach (BasicBlock domFrontier in dfPhiBlock.DominanceFrontiers) foreach (BasicBlock domFrontier in dfPhiBlock.DominanceFrontiers)
{ {
if (globalDefs[domFrontier.Index].AddPhi(reg)) if (globalDefs[domFrontier.Index].AddPhi(key))
{ {
dfPhiBlocks.Enqueue(domFrontier); dfPhiBlocks.Enqueue(domFrontier);
} }
} }
} }
} }
Array.Clear(localDefs, 0, localDefs.Length);
} }
// Second pass, rename variables with definitions on different blocks. // Second pass, rename variables with definitions on different blocks.
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
{ {
Operand[] localDefs = new Operand[RegisterConsts.TotalCount]; for (Node node = block.Operations.First; node != null; node = node.ListNext)
Node node = block.Operations.First;
Operand RenameGlobal(Operand operand)
{ {
if (operand != null && operand.Kind == OperandKind.Register) if (node is not Operation operation)
{ {
int key = GetIdFromRegister(operand.GetRegister()); continue;
}
for (int index = 0; index < operation.SourcesCount; index++)
{
Operand src = operation.GetSource(index);
if (TryGetId(src, out int key))
{
Operand local = localDefs[key]; Operand local = localDefs[key];
if (local == null) if (local is null)
{ {
local = FindDef(globalDefs, block, operand); local = FindDef(globalDefs, block, src);
localDefs[key] = local; localDefs[key] = local;
} }
operand = local; operation.SetSource(index, local);
} }
return operand;
}
while (node != null)
{
if (node is Operation operation)
{
for (int index = 0; index < operation.SourcesCount; index++)
{
operation.SetSource(index, RenameGlobal(operation.GetSource(index)));
} }
} }
node = node.ListNext; Array.Clear(localDefs, 0, localDefs.Length);
}
} }
} }
private static Operand FindDef(DefMap[] globalDefs, BasicBlock current, Operand operand) private static Operand FindDef(DefMap[] globalDefs, BasicBlock current, Operand operand)
{ {
if (globalDefs[current.Index].HasPhi(operand.GetRegister())) if (globalDefs[current.Index].HasPhi(GetId(operand)))
{ {
return InsertPhi(globalDefs, current, operand); return InsertPhi(globalDefs, current, operand);
} }
@ -191,14 +172,14 @@ namespace ARMeilleure.Translation
{ {
DefMap defMap = globalDefs[current.Index]; DefMap defMap = globalDefs[current.Index];
Register reg = operand.GetRegister(); int key = GetId(operand);
if (defMap.TryGetOperand(reg, out Operand lastDef)) if (defMap.TryGetOperand(key, out Operand lastDef))
{ {
return lastDef; return lastDef;
} }
if (defMap.HasPhi(reg)) if (defMap.HasPhi(key))
{ {
return InsertPhi(globalDefs, current, operand); return InsertPhi(globalDefs, current, operand);
} }
@ -223,7 +204,7 @@ namespace ARMeilleure.Translation
AddPhi(block, phi); AddPhi(block, phi);
globalDefs[block.Index].TryAddOperand(operand.GetRegister(), local); globalDefs[block.Index].TryAddOperand(GetId(operand), local);
for (int index = 0; index < block.Predecessors.Count; index++) for (int index = 0; index < block.Predecessors.Count; index++)
{ {
@ -258,44 +239,45 @@ namespace ARMeilleure.Translation
} }
} }
private static int GetIdFromRegister(Register reg) private static bool TryGetId(Operand operand, out int result)
{ {
if (operand is { Kind: OperandKind.Register })
{
Register reg = operand.GetRegister();
if (reg.Type == RegisterType.Integer) if (reg.Type == RegisterType.Integer)
{ {
return reg.Index; result = reg.Index;
} }
else if (reg.Type == RegisterType.Vector) else if (reg.Type == RegisterType.Vector)
{ {
return RegisterConsts.IntRegsCount + reg.Index; result = RegisterConsts.IntRegsCount + reg.Index;
} }
else if (reg.Type == RegisterType.Flag) else if (reg.Type == RegisterType.Flag)
{ {
return RegisterConsts.IntAndVecRegsCount + reg.Index; result = RegisterConsts.IntAndVecRegsCount + reg.Index;
} }
else /* if (reg.Type == RegisterType.FpFlag) */ else /* if (reg.Type == RegisterType.FpFlag) */
{ {
return RegisterConsts.FpFlagsOffset + reg.Index; result = RegisterConsts.FpFlagsOffset + reg.Index;
}
} }
private static Register GetRegisterFromId(int id) return true;
}
result = -1;
return false;
}
private static int GetId(Operand operand)
{ {
if (id < RegisterConsts.IntRegsCount) if (!TryGetId(operand, out int key))
{ {
return new Register(id, RegisterType.Integer); Debug.Fail("OperandKind must be Register.");
}
else if (id < RegisterConsts.IntAndVecRegsCount)
{
return new Register(id - RegisterConsts.IntRegsCount, RegisterType.Vector);
}
else if (id < RegisterConsts.FpFlagsOffset)
{
return new Register(id - RegisterConsts.IntAndVecRegsCount, RegisterType.Flag);
}
else /* if (id < RegisterConsts.TotalCount) */
{
return new Register(id - RegisterConsts.FpFlagsOffset, RegisterType.FpFlag);
} }
return key;
} }
} }
} }