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

View file

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