| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444 |
- using ARMeilleure.IntermediateRepresentation;
- using ARMeilleure.Translation;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Numerics;
- using static ARMeilleure.IntermediateRepresentation.OperandHelper;
- using static ARMeilleure.IntermediateRepresentation.OperationHelper;
- namespace ARMeilleure.CodeGen.RegisterAllocators
- {
- class HybridAllocator : IRegisterAllocator
- {
- private const int RegistersCount = 16;
- private const int MaxIROperands = 4;
- private struct BlockInfo
- {
- public bool HasCall { get; }
- public int IntFixedRegisters { get; }
- public int VecFixedRegisters { get; }
- public BlockInfo(bool hasCall, int intFixedRegisters, int vecFixedRegisters)
- {
- HasCall = hasCall;
- IntFixedRegisters = intFixedRegisters;
- VecFixedRegisters = vecFixedRegisters;
- }
- }
- private class LocalInfo
- {
- public int Uses { get; set; }
- public int UseCount { get; set; }
- public bool PreAllocated { get; set; }
- public int Register { get; set; }
- public int SpillOffset { get; set; }
- public int Sequence { get; set; }
- public Operand Temp { get; set; }
- public OperandType Type { get; }
- private int _first;
- private int _last;
- public bool IsBlockLocal => _first == _last;
- public LocalInfo(OperandType type, int uses)
- {
- Uses = uses;
- Type = type;
- _first = -1;
- _last = -1;
- }
- public void SetBlockIndex(int blkIndex)
- {
- if (_first == -1 || blkIndex < _first)
- {
- _first = blkIndex;
- }
- if (_last == -1 || blkIndex > _last)
- {
- _last = blkIndex;
- }
- }
- }
- public AllocationResult RunPass(
- ControlFlowGraph cfg,
- StackAllocator stackAlloc,
- RegisterMasks regMasks)
- {
- int intUsedRegisters = 0;
- int vecUsedRegisters = 0;
- int intFreeRegisters = regMasks.IntAvailableRegisters;
- int vecFreeRegisters = regMasks.VecAvailableRegisters;
- BlockInfo[] blockInfo = new BlockInfo[cfg.Blocks.Count];
- List<LocalInfo> locInfo = new List<LocalInfo>();
- for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--)
- {
- BasicBlock block = cfg.PostOrderBlocks[index];
- int intFixedRegisters = 0;
- int vecFixedRegisters = 0;
- bool hasCall = false;
- for (Node node = block.Operations.First; node != null; node = node.ListNext)
- {
- if (node is Operation operation && operation.Instruction == Instruction.Call)
- {
- hasCall = true;
- }
- for (int srcIndex = 0; srcIndex < node.SourcesCount; srcIndex++)
- {
- Operand source = node.GetSource(srcIndex);
- if (source.Kind == OperandKind.LocalVariable)
- {
- locInfo[source.AsInt32() - 1].SetBlockIndex(block.Index);
- }
- else if (source.Kind == OperandKind.Memory)
- {
- MemoryOperand memOp = (MemoryOperand)source;
- if (memOp.BaseAddress != null)
- {
- locInfo[memOp.BaseAddress.AsInt32() - 1].SetBlockIndex(block.Index);
- }
- if (memOp.Index != null)
- {
- locInfo[memOp.Index.AsInt32() - 1].SetBlockIndex(block.Index);
- }
- }
- }
- for (int dstIndex = 0; dstIndex < node.DestinationsCount; dstIndex++)
- {
- Operand dest = node.GetDestination(dstIndex);
- if (dest.Kind == OperandKind.LocalVariable)
- {
- LocalInfo info;
- if (dest.Value != 0)
- {
- info = locInfo[dest.AsInt32() - 1];
- }
- else
- {
- dest.NumberLocal(locInfo.Count + 1);
- info = new LocalInfo(dest.Type, UsesCount(dest));
- locInfo.Add(info);
- }
- info.SetBlockIndex(block.Index);
- }
- else if (dest.Kind == OperandKind.Register)
- {
- if (dest.Type.IsInteger())
- {
- intFixedRegisters |= 1 << dest.GetRegister().Index;
- }
- else
- {
- vecFixedRegisters |= 1 << dest.GetRegister().Index;
- }
- }
- }
- }
- blockInfo[block.Index] = new BlockInfo(hasCall, intFixedRegisters, vecFixedRegisters);
- }
- int sequence = 0;
- for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--)
- {
- BasicBlock block = cfg.PostOrderBlocks[index];
- BlockInfo blkInfo = blockInfo[block.Index];
- int intLocalFreeRegisters = intFreeRegisters & ~blkInfo.IntFixedRegisters;
- int vecLocalFreeRegisters = vecFreeRegisters & ~blkInfo.VecFixedRegisters;
- int intCallerSavedRegisters = blkInfo.HasCall ? regMasks.IntCallerSavedRegisters : 0;
- int vecCallerSavedRegisters = blkInfo.HasCall ? regMasks.VecCallerSavedRegisters : 0;
- int intSpillTempRegisters = SelectSpillTemps(
- intCallerSavedRegisters & ~blkInfo.IntFixedRegisters,
- intLocalFreeRegisters);
- int vecSpillTempRegisters = SelectSpillTemps(
- vecCallerSavedRegisters & ~blkInfo.VecFixedRegisters,
- vecLocalFreeRegisters);
- intLocalFreeRegisters &= ~(intSpillTempRegisters | intCallerSavedRegisters);
- vecLocalFreeRegisters &= ~(vecSpillTempRegisters | vecCallerSavedRegisters);
- for (Node node = block.Operations.First; node != null; node = node.ListNext)
- {
- int intLocalUse = 0;
- int vecLocalUse = 0;
- void AllocateRegister(Operand source, MemoryOperand memOp, int srcIndex)
- {
- LocalInfo info = locInfo[source.AsInt32() - 1];
- info.UseCount++;
- Debug.Assert(info.UseCount <= info.Uses);
- if (info.Register != -1)
- {
- Operand reg = Register(info.Register, source.Type.ToRegisterType(), source.Type);
- if (memOp != null)
- {
- if (srcIndex == 0)
- {
- memOp.BaseAddress = reg;
- }
- else /* if (srcIndex == 1) */
- {
- memOp.Index = reg;
- }
- }
- else
- {
- node.SetSource(srcIndex, reg);
- }
- if (info.UseCount == info.Uses && !info.PreAllocated)
- {
- if (source.Type.IsInteger())
- {
- intLocalFreeRegisters |= 1 << info.Register;
- }
- else
- {
- vecLocalFreeRegisters |= 1 << info.Register;
- }
- }
- }
- else
- {
- Operand temp = info.Temp;
- if (temp == null || info.Sequence != sequence)
- {
- temp = source.Type.IsInteger()
- ? GetSpillTemp(source, intSpillTempRegisters, ref intLocalUse)
- : GetSpillTemp(source, vecSpillTempRegisters, ref vecLocalUse);
- info.Sequence = sequence;
- info.Temp = temp;
- }
- if (memOp != null)
- {
- if (srcIndex == 0)
- {
- memOp.BaseAddress = temp;
- }
- else /* if (srcIndex == 1) */
- {
- memOp.Index = temp;
- }
- }
- else
- {
- node.SetSource(srcIndex, temp);
- }
- Operation fillOp = Operation(Instruction.Fill, temp, Const(info.SpillOffset));
- block.Operations.AddBefore(node, fillOp);
- }
- }
- for (int srcIndex = 0; srcIndex < node.SourcesCount; srcIndex++)
- {
- Operand source = node.GetSource(srcIndex);
- if (source.Kind == OperandKind.LocalVariable)
- {
- AllocateRegister(source, null, srcIndex);
- }
- else if (source.Kind == OperandKind.Memory)
- {
- MemoryOperand memOp = (MemoryOperand)source;
- if (memOp.BaseAddress != null)
- {
- AllocateRegister(memOp.BaseAddress, memOp, 0);
- }
- if (memOp.Index != null)
- {
- AllocateRegister(memOp.Index, memOp, 1);
- }
- }
- }
- int intLocalAsg = 0;
- int vecLocalAsg = 0;
- for (int dstIndex = 0; dstIndex < node.DestinationsCount; dstIndex++)
- {
- Operand dest = node.GetDestination(dstIndex);
- if (dest.Kind != OperandKind.LocalVariable)
- {
- continue;
- }
- LocalInfo info = locInfo[dest.AsInt32() - 1];
- if (info.UseCount == 0 && !info.PreAllocated)
- {
- int mask = dest.Type.IsInteger()
- ? intLocalFreeRegisters
- : vecLocalFreeRegisters;
- if (info.IsBlockLocal && mask != 0)
- {
- int selectedReg = BitOperations.TrailingZeroCount(mask);
- info.Register = selectedReg;
- if (dest.Type.IsInteger())
- {
- intLocalFreeRegisters &= ~(1 << selectedReg);
- intUsedRegisters |= 1 << selectedReg;
- }
- else
- {
- vecLocalFreeRegisters &= ~(1 << selectedReg);
- vecUsedRegisters |= 1 << selectedReg;
- }
- }
- else
- {
- info.Register = -1;
- info.SpillOffset = stackAlloc.Allocate(dest.Type.GetSizeInBytes());
- }
- }
- info.UseCount++;
- Debug.Assert(info.UseCount <= info.Uses);
- if (info.Register != -1)
- {
- node.SetDestination(dstIndex, Register(info.Register, dest.Type.ToRegisterType(), dest.Type));
- }
- else
- {
- Operand temp = info.Temp;
- if (temp == null || info.Sequence != sequence)
- {
- temp = dest.Type.IsInteger()
- ? GetSpillTemp(dest, intSpillTempRegisters, ref intLocalAsg)
- : GetSpillTemp(dest, vecSpillTempRegisters, ref vecLocalAsg);
- info.Sequence = sequence;
- info.Temp = temp;
- }
- node.SetDestination(dstIndex, temp);
- Operation spillOp = Operation(Instruction.Spill, null, Const(info.SpillOffset), temp);
- block.Operations.AddAfter(node, spillOp);
- node = spillOp;
- }
- }
- sequence++;
- intUsedRegisters |= intLocalAsg | intLocalUse;
- vecUsedRegisters |= vecLocalAsg | vecLocalUse;
- }
- }
- return new AllocationResult(intUsedRegisters, vecUsedRegisters, stackAlloc.TotalSize);
- }
- private static int SelectSpillTemps(int mask0, int mask1)
- {
- int selection = 0;
- int count = 0;
- while (count < MaxIROperands && mask0 != 0)
- {
- int mask = mask0 & -mask0;
- selection |= mask;
- mask0 &= ~mask;
- count++;
- }
- while (count < MaxIROperands && mask1 != 0)
- {
- int mask = mask1 & -mask1;
- selection |= mask;
- mask1 &= ~mask;
- count++;
- }
- Debug.Assert(count == MaxIROperands, "No enough registers for spill temps.");
- return selection;
- }
- private static Operand GetSpillTemp(Operand local, int freeMask, ref int useMask)
- {
- int selectedReg = BitOperations.TrailingZeroCount(freeMask & ~useMask);
- useMask |= 1 << selectedReg;
- return Register(selectedReg, local.Type.ToRegisterType(), local.Type);
- }
- private static int UsesCount(Operand local)
- {
- return local.Assignments.Count + local.Uses.Count;
- }
- private static IEnumerable<BasicBlock> Successors(BasicBlock block)
- {
- if (block.Next != null)
- {
- yield return block.Next;
- }
- if (block.Branch != null)
- {
- yield return block.Branch;
- }
- }
- }
- }
|