forked from Mirror/Ryujinx
Reduce allocation during SSA construction (#2162)
* Reduce allocation during SSA construction * Re-trigger CI
This commit is contained in:
parent
529df341f1
commit
8b3eba7e13
2 changed files with 111 additions and 127 deletions
|
@ -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));
|
||||||
|
|
|
@ -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())];
|
|
||||||
|
|
||||||
operand = local ?? operand;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 dest = operation.Destination;
|
|
||||||
|
|
||||||
if (dest != null && dest.Kind == OperandKind.Register)
|
|
||||||
{
|
|
||||||
Operand local = Local(dest.Type);
|
|
||||||
|
|
||||||
localDefs[GetIdFromRegister(dest.GetRegister())] = local;
|
|
||||||
|
|
||||||
operation.Destination = local;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
node = node.ListNext;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int index = 0; index < RegisterConsts.TotalCount; index++)
|
|
||||||
{
|
|
||||||
Operand local = localDefs[index];
|
|
||||||
|
|
||||||
if (local == null)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Register reg = GetRegisterFromId(index);
|
for (int index = 0; index < operation.SourcesCount; index++)
|
||||||
|
{
|
||||||
|
Operand src = operation.GetSource(index);
|
||||||
|
|
||||||
globalDefs[block.Index].TryAddOperand(reg, local);
|
if (TryGetId(src, out int srcKey))
|
||||||
|
{
|
||||||
|
Operand local = localDefs[srcKey] ?? src;
|
||||||
|
|
||||||
|
operation.SetSource(index, local);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand dest = operation.Destination;
|
||||||
|
|
||||||
|
if (TryGetId(dest, out int destKey))
|
||||||
|
{
|
||||||
|
Operand local = Local(dest.Type);
|
||||||
|
|
||||||
|
localDefs[destKey] = local;
|
||||||
|
|
||||||
|
operation.Destination = local;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int key = 0; key < localDefs.Length; key++)
|
||||||
|
{
|
||||||
|
Operand local = localDefs[key];
|
||||||
|
|
||||||
|
if (local is null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
globalDefs[block.Index].TryAddOperand(key, 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;
|
||||||
|
|
||||||
Operand local = localDefs[key];
|
|
||||||
|
|
||||||
if (local == null)
|
|
||||||
{
|
|
||||||
local = FindDef(globalDefs, block, operand);
|
|
||||||
|
|
||||||
localDefs[key] = local;
|
|
||||||
}
|
|
||||||
|
|
||||||
operand = local;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return operand;
|
for (int index = 0; index < operation.SourcesCount; index++)
|
||||||
}
|
|
||||||
|
|
||||||
while (node != null)
|
|
||||||
{
|
|
||||||
if (node is Operation operation)
|
|
||||||
{
|
{
|
||||||
for (int index = 0; index < operation.SourcesCount; index++)
|
Operand src = operation.GetSource(index);
|
||||||
|
|
||||||
|
if (TryGetId(src, out int key))
|
||||||
{
|
{
|
||||||
operation.SetSource(index, RenameGlobal(operation.GetSource(index)));
|
Operand local = localDefs[key];
|
||||||
|
|
||||||
|
if (local is null)
|
||||||
|
{
|
||||||
|
local = FindDef(globalDefs, block, src);
|
||||||
|
localDefs[key] = local;
|
||||||
|
}
|
||||||
|
|
||||||
|
operation.SetSource(index, local);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 (reg.Type == RegisterType.Integer)
|
if (operand is { Kind: OperandKind.Register })
|
||||||
{
|
{
|
||||||
return reg.Index;
|
Register reg = operand.GetRegister();
|
||||||
}
|
|
||||||
else if (reg.Type == RegisterType.Vector)
|
if (reg.Type == RegisterType.Integer)
|
||||||
{
|
{
|
||||||
return RegisterConsts.IntRegsCount + reg.Index;
|
result = reg.Index;
|
||||||
}
|
}
|
||||||
else if (reg.Type == RegisterType.Flag)
|
else if (reg.Type == RegisterType.Vector)
|
||||||
{
|
{
|
||||||
return RegisterConsts.IntAndVecRegsCount + reg.Index;
|
result = RegisterConsts.IntRegsCount + reg.Index;
|
||||||
}
|
}
|
||||||
else /* if (reg.Type == RegisterType.FpFlag) */
|
else if (reg.Type == RegisterType.Flag)
|
||||||
{
|
{
|
||||||
return RegisterConsts.FpFlagsOffset + reg.Index;
|
result = RegisterConsts.IntAndVecRegsCount + reg.Index;
|
||||||
|
}
|
||||||
|
else /* if (reg.Type == RegisterType.FpFlag) */
|
||||||
|
{
|
||||||
|
result = RegisterConsts.FpFlagsOffset + reg.Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result = -1;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Register GetRegisterFromId(int id)
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue