mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-07-25 08:27:11 +02:00
Move solution and projects to src
This commit is contained in:
parent
cd124bda58
commit
cee7121058
3466 changed files with 55 additions and 55 deletions
159
src/ARMeilleure/IntermediateRepresentation/BasicBlock.cs
Normal file
159
src/ARMeilleure/IntermediateRepresentation/BasicBlock.cs
Normal file
|
@ -0,0 +1,159 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
class BasicBlock : IEquatable<BasicBlock>, IIntrusiveListNode<BasicBlock>
|
||||
{
|
||||
private const uint MaxSuccessors = 2;
|
||||
|
||||
private int _succCount;
|
||||
private BasicBlock _succ0;
|
||||
private BasicBlock _succ1;
|
||||
private HashSet<BasicBlock> _domFrontiers;
|
||||
|
||||
public int Index { get; set; }
|
||||
public BasicBlockFrequency Frequency { get; set; }
|
||||
public BasicBlock ListPrevious { get; set; }
|
||||
public BasicBlock ListNext { get; set; }
|
||||
public IntrusiveList<Operation> Operations { get; }
|
||||
public List<BasicBlock> Predecessors { get; }
|
||||
public BasicBlock ImmediateDominator { get; set; }
|
||||
|
||||
public int SuccessorsCount => _succCount;
|
||||
|
||||
public HashSet<BasicBlock> DominanceFrontiers
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_domFrontiers == null)
|
||||
{
|
||||
_domFrontiers = new HashSet<BasicBlock>();
|
||||
}
|
||||
|
||||
return _domFrontiers;
|
||||
}
|
||||
}
|
||||
|
||||
public BasicBlock() : this(index: -1) { }
|
||||
|
||||
public BasicBlock(int index)
|
||||
{
|
||||
Operations = new IntrusiveList<Operation>();
|
||||
Predecessors = new List<BasicBlock>();
|
||||
|
||||
Index = index;
|
||||
}
|
||||
|
||||
public void AddSuccessor(BasicBlock block)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(block);
|
||||
|
||||
if ((uint)_succCount + 1 > MaxSuccessors)
|
||||
{
|
||||
ThrowSuccessorOverflow();
|
||||
}
|
||||
|
||||
block.Predecessors.Add(this);
|
||||
|
||||
GetSuccessorUnsafe(_succCount++) = block;
|
||||
}
|
||||
|
||||
public void RemoveSuccessor(int index)
|
||||
{
|
||||
if ((uint)index >= (uint)_succCount)
|
||||
{
|
||||
ThrowOutOfRange(nameof(index));
|
||||
}
|
||||
|
||||
ref BasicBlock oldBlock = ref GetSuccessorUnsafe(index);
|
||||
|
||||
oldBlock.Predecessors.Remove(this);
|
||||
oldBlock = null;
|
||||
|
||||
if (index == 0)
|
||||
{
|
||||
_succ0 = _succ1;
|
||||
}
|
||||
|
||||
_succCount--;
|
||||
}
|
||||
|
||||
public BasicBlock GetSuccessor(int index)
|
||||
{
|
||||
if ((uint)index >= (uint)_succCount)
|
||||
{
|
||||
ThrowOutOfRange(nameof(index));
|
||||
}
|
||||
|
||||
return GetSuccessorUnsafe(index);
|
||||
}
|
||||
|
||||
private ref BasicBlock GetSuccessorUnsafe(int index)
|
||||
{
|
||||
return ref Unsafe.Add(ref _succ0, index);
|
||||
}
|
||||
|
||||
public void SetSuccessor(int index, BasicBlock block)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(block);
|
||||
|
||||
if ((uint)index >= (uint)_succCount)
|
||||
{
|
||||
ThrowOutOfRange(nameof(index));
|
||||
}
|
||||
|
||||
ref BasicBlock oldBlock = ref GetSuccessorUnsafe(index);
|
||||
|
||||
oldBlock.Predecessors.Remove(this);
|
||||
block.Predecessors.Add(this);
|
||||
|
||||
oldBlock = block;
|
||||
}
|
||||
|
||||
public void Append(Operation node)
|
||||
{
|
||||
Operation last = Operations.Last;
|
||||
|
||||
// Append node before terminal or to end if no terminal.
|
||||
if (last == default)
|
||||
{
|
||||
Operations.AddLast(node);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch (last.Instruction)
|
||||
{
|
||||
case Instruction.Return:
|
||||
case Instruction.Tailcall:
|
||||
case Instruction.BranchIf:
|
||||
Operations.AddBefore(last, node);
|
||||
break;
|
||||
|
||||
default:
|
||||
Operations.AddLast(node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ThrowOutOfRange(string name) => throw new ArgumentOutOfRangeException(name);
|
||||
private static void ThrowSuccessorOverflow() => throw new OverflowException($"BasicBlock can only have {MaxSuccessors} successors.");
|
||||
|
||||
public bool Equals(BasicBlock other)
|
||||
{
|
||||
return other == this;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return Equals(obj as BasicBlock);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
enum BasicBlockFrequency
|
||||
{
|
||||
Default,
|
||||
Cold
|
||||
}
|
||||
}
|
24
src/ARMeilleure/IntermediateRepresentation/Comparison.cs
Normal file
24
src/ARMeilleure/IntermediateRepresentation/Comparison.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
enum Comparison
|
||||
{
|
||||
Equal = 0,
|
||||
NotEqual = 1,
|
||||
Greater = 2,
|
||||
LessOrEqual = 3,
|
||||
GreaterUI = 4,
|
||||
LessOrEqualUI = 5,
|
||||
GreaterOrEqual = 6,
|
||||
Less = 7,
|
||||
GreaterOrEqualUI = 8,
|
||||
LessUI = 9
|
||||
}
|
||||
|
||||
static class ComparisonExtensions
|
||||
{
|
||||
public static Comparison Invert(this Comparison comp)
|
||||
{
|
||||
return (Comparison)((int)comp ^ 1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
interface IIntrusiveListNode<T>
|
||||
{
|
||||
T ListPrevious { get; set; }
|
||||
T ListNext { get; set; }
|
||||
}
|
||||
}
|
72
src/ARMeilleure/IntermediateRepresentation/Instruction.cs
Normal file
72
src/ARMeilleure/IntermediateRepresentation/Instruction.cs
Normal file
|
@ -0,0 +1,72 @@
|
|||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
enum Instruction : ushort
|
||||
{
|
||||
Add,
|
||||
BitwiseAnd,
|
||||
BitwiseExclusiveOr,
|
||||
BitwiseNot,
|
||||
BitwiseOr,
|
||||
BranchIf,
|
||||
ByteSwap,
|
||||
Call,
|
||||
Compare,
|
||||
CompareAndSwap,
|
||||
CompareAndSwap16,
|
||||
CompareAndSwap8,
|
||||
ConditionalSelect,
|
||||
ConvertI64ToI32,
|
||||
ConvertToFP,
|
||||
ConvertToFPUI,
|
||||
Copy,
|
||||
CountLeadingZeros,
|
||||
Divide,
|
||||
DivideUI,
|
||||
Load,
|
||||
Load16,
|
||||
Load8,
|
||||
LoadArgument,
|
||||
MemoryBarrier,
|
||||
Multiply,
|
||||
Multiply64HighSI,
|
||||
Multiply64HighUI,
|
||||
Negate,
|
||||
Return,
|
||||
RotateRight,
|
||||
ShiftLeft,
|
||||
ShiftRightSI,
|
||||
ShiftRightUI,
|
||||
SignExtend16,
|
||||
SignExtend32,
|
||||
SignExtend8,
|
||||
StackAlloc,
|
||||
Store,
|
||||
Store16,
|
||||
Store8,
|
||||
Subtract,
|
||||
Tailcall,
|
||||
VectorCreateScalar,
|
||||
VectorExtract,
|
||||
VectorExtract16,
|
||||
VectorExtract8,
|
||||
VectorInsert,
|
||||
VectorInsert16,
|
||||
VectorInsert8,
|
||||
VectorOne,
|
||||
VectorZero,
|
||||
VectorZeroUpper64,
|
||||
VectorZeroUpper96,
|
||||
ZeroExtend16,
|
||||
ZeroExtend32,
|
||||
ZeroExtend8,
|
||||
|
||||
Clobber,
|
||||
Extended,
|
||||
Fill,
|
||||
LoadFromContext,
|
||||
Phi,
|
||||
Spill,
|
||||
SpillArg,
|
||||
StoreToContext
|
||||
}
|
||||
}
|
636
src/ARMeilleure/IntermediateRepresentation/Intrinsic.cs
Normal file
636
src/ARMeilleure/IntermediateRepresentation/Intrinsic.cs
Normal file
|
@ -0,0 +1,636 @@
|
|||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
enum Intrinsic : ushort
|
||||
{
|
||||
// X86 (SSE and AVX)
|
||||
|
||||
X86Addpd,
|
||||
X86Addps,
|
||||
X86Addsd,
|
||||
X86Addss,
|
||||
X86Aesdec,
|
||||
X86Aesdeclast,
|
||||
X86Aesenc,
|
||||
X86Aesenclast,
|
||||
X86Aesimc,
|
||||
X86Andnpd,
|
||||
X86Andnps,
|
||||
X86Andpd,
|
||||
X86Andps,
|
||||
X86Blendvpd,
|
||||
X86Blendvps,
|
||||
X86Cmppd,
|
||||
X86Cmpps,
|
||||
X86Cmpsd,
|
||||
X86Cmpss,
|
||||
X86Comisdeq,
|
||||
X86Comisdge,
|
||||
X86Comisdlt,
|
||||
X86Comisseq,
|
||||
X86Comissge,
|
||||
X86Comisslt,
|
||||
X86Crc32,
|
||||
X86Crc32_16,
|
||||
X86Crc32_8,
|
||||
X86Cvtdq2pd,
|
||||
X86Cvtdq2ps,
|
||||
X86Cvtpd2dq,
|
||||
X86Cvtpd2ps,
|
||||
X86Cvtps2dq,
|
||||
X86Cvtps2pd,
|
||||
X86Cvtsd2si,
|
||||
X86Cvtsd2ss,
|
||||
X86Cvtsi2sd,
|
||||
X86Cvtsi2si,
|
||||
X86Cvtsi2ss,
|
||||
X86Cvtss2sd,
|
||||
X86Cvtss2si,
|
||||
X86Divpd,
|
||||
X86Divps,
|
||||
X86Divsd,
|
||||
X86Divss,
|
||||
X86Gf2p8affineqb,
|
||||
X86Haddpd,
|
||||
X86Haddps,
|
||||
X86Insertps,
|
||||
X86Ldmxcsr,
|
||||
X86Maxpd,
|
||||
X86Maxps,
|
||||
X86Maxsd,
|
||||
X86Maxss,
|
||||
X86Minpd,
|
||||
X86Minps,
|
||||
X86Minsd,
|
||||
X86Minss,
|
||||
X86Movhlps,
|
||||
X86Movlhps,
|
||||
X86Movss,
|
||||
X86Mulpd,
|
||||
X86Mulps,
|
||||
X86Mulsd,
|
||||
X86Mulss,
|
||||
X86Paddb,
|
||||
X86Paddd,
|
||||
X86Paddq,
|
||||
X86Paddw,
|
||||
X86Palignr,
|
||||
X86Pand,
|
||||
X86Pandn,
|
||||
X86Pavgb,
|
||||
X86Pavgw,
|
||||
X86Pblendvb,
|
||||
X86Pclmulqdq,
|
||||
X86Pcmpeqb,
|
||||
X86Pcmpeqd,
|
||||
X86Pcmpeqq,
|
||||
X86Pcmpeqw,
|
||||
X86Pcmpgtb,
|
||||
X86Pcmpgtd,
|
||||
X86Pcmpgtq,
|
||||
X86Pcmpgtw,
|
||||
X86Pmaxsb,
|
||||
X86Pmaxsd,
|
||||
X86Pmaxsw,
|
||||
X86Pmaxub,
|
||||
X86Pmaxud,
|
||||
X86Pmaxuw,
|
||||
X86Pminsb,
|
||||
X86Pminsd,
|
||||
X86Pminsw,
|
||||
X86Pminub,
|
||||
X86Pminud,
|
||||
X86Pminuw,
|
||||
X86Pmovsxbw,
|
||||
X86Pmovsxdq,
|
||||
X86Pmovsxwd,
|
||||
X86Pmovzxbw,
|
||||
X86Pmovzxdq,
|
||||
X86Pmovzxwd,
|
||||
X86Pmulld,
|
||||
X86Pmullw,
|
||||
X86Popcnt,
|
||||
X86Por,
|
||||
X86Pshufb,
|
||||
X86Pshufd,
|
||||
X86Pslld,
|
||||
X86Pslldq,
|
||||
X86Psllq,
|
||||
X86Psllw,
|
||||
X86Psrad,
|
||||
X86Psraw,
|
||||
X86Psrld,
|
||||
X86Psrlq,
|
||||
X86Psrldq,
|
||||
X86Psrlw,
|
||||
X86Psubb,
|
||||
X86Psubd,
|
||||
X86Psubq,
|
||||
X86Psubw,
|
||||
X86Punpckhbw,
|
||||
X86Punpckhdq,
|
||||
X86Punpckhqdq,
|
||||
X86Punpckhwd,
|
||||
X86Punpcklbw,
|
||||
X86Punpckldq,
|
||||
X86Punpcklqdq,
|
||||
X86Punpcklwd,
|
||||
X86Pxor,
|
||||
X86Rcpps,
|
||||
X86Rcpss,
|
||||
X86Roundpd,
|
||||
X86Roundps,
|
||||
X86Roundsd,
|
||||
X86Roundss,
|
||||
X86Rsqrtps,
|
||||
X86Rsqrtss,
|
||||
X86Sha256Msg1,
|
||||
X86Sha256Msg2,
|
||||
X86Sha256Rnds2,
|
||||
X86Shufpd,
|
||||
X86Shufps,
|
||||
X86Sqrtpd,
|
||||
X86Sqrtps,
|
||||
X86Sqrtsd,
|
||||
X86Sqrtss,
|
||||
X86Stmxcsr,
|
||||
X86Subpd,
|
||||
X86Subps,
|
||||
X86Subsd,
|
||||
X86Subss,
|
||||
X86Unpckhpd,
|
||||
X86Unpckhps,
|
||||
X86Unpcklpd,
|
||||
X86Unpcklps,
|
||||
X86Vcvtph2ps,
|
||||
X86Vcvtps2ph,
|
||||
X86Vfmadd231pd,
|
||||
X86Vfmadd231ps,
|
||||
X86Vfmadd231sd,
|
||||
X86Vfmadd231ss,
|
||||
X86Vfmsub231sd,
|
||||
X86Vfmsub231ss,
|
||||
X86Vfnmadd231pd,
|
||||
X86Vfnmadd231ps,
|
||||
X86Vfnmadd231sd,
|
||||
X86Vfnmadd231ss,
|
||||
X86Vfnmsub231sd,
|
||||
X86Vfnmsub231ss,
|
||||
X86Vpternlogd,
|
||||
X86Xorpd,
|
||||
X86Xorps,
|
||||
|
||||
// Arm64 (FP and Advanced SIMD)
|
||||
|
||||
Arm64AbsS,
|
||||
Arm64AbsV,
|
||||
Arm64AddhnV,
|
||||
Arm64AddpS,
|
||||
Arm64AddpV,
|
||||
Arm64AddvV,
|
||||
Arm64AddS,
|
||||
Arm64AddV,
|
||||
Arm64AesdV,
|
||||
Arm64AeseV,
|
||||
Arm64AesimcV,
|
||||
Arm64AesmcV,
|
||||
Arm64AndV,
|
||||
Arm64BicVi,
|
||||
Arm64BicV,
|
||||
Arm64BifV,
|
||||
Arm64BitV,
|
||||
Arm64BslV,
|
||||
Arm64ClsV,
|
||||
Arm64ClzV,
|
||||
Arm64CmeqS,
|
||||
Arm64CmeqV,
|
||||
Arm64CmeqSz,
|
||||
Arm64CmeqVz,
|
||||
Arm64CmgeS,
|
||||
Arm64CmgeV,
|
||||
Arm64CmgeSz,
|
||||
Arm64CmgeVz,
|
||||
Arm64CmgtS,
|
||||
Arm64CmgtV,
|
||||
Arm64CmgtSz,
|
||||
Arm64CmgtVz,
|
||||
Arm64CmhiS,
|
||||
Arm64CmhiV,
|
||||
Arm64CmhsS,
|
||||
Arm64CmhsV,
|
||||
Arm64CmleSz,
|
||||
Arm64CmleVz,
|
||||
Arm64CmltSz,
|
||||
Arm64CmltVz,
|
||||
Arm64CmtstS,
|
||||
Arm64CmtstV,
|
||||
Arm64CntV,
|
||||
Arm64DupSe,
|
||||
Arm64DupVe,
|
||||
Arm64DupGp,
|
||||
Arm64EorV,
|
||||
Arm64ExtV,
|
||||
Arm64FabdS,
|
||||
Arm64FabdV,
|
||||
Arm64FabsV,
|
||||
Arm64FabsS,
|
||||
Arm64FacgeS,
|
||||
Arm64FacgeV,
|
||||
Arm64FacgtS,
|
||||
Arm64FacgtV,
|
||||
Arm64FaddpS,
|
||||
Arm64FaddpV,
|
||||
Arm64FaddV,
|
||||
Arm64FaddS,
|
||||
Arm64FccmpeS,
|
||||
Arm64FccmpS,
|
||||
Arm64FcmeqS,
|
||||
Arm64FcmeqV,
|
||||
Arm64FcmeqSz,
|
||||
Arm64FcmeqVz,
|
||||
Arm64FcmgeS,
|
||||
Arm64FcmgeV,
|
||||
Arm64FcmgeSz,
|
||||
Arm64FcmgeVz,
|
||||
Arm64FcmgtS,
|
||||
Arm64FcmgtV,
|
||||
Arm64FcmgtSz,
|
||||
Arm64FcmgtVz,
|
||||
Arm64FcmleSz,
|
||||
Arm64FcmleVz,
|
||||
Arm64FcmltSz,
|
||||
Arm64FcmltVz,
|
||||
Arm64FcmpeS,
|
||||
Arm64FcmpS,
|
||||
Arm64FcselS,
|
||||
Arm64FcvtasS,
|
||||
Arm64FcvtasV,
|
||||
Arm64FcvtasGp,
|
||||
Arm64FcvtauS,
|
||||
Arm64FcvtauV,
|
||||
Arm64FcvtauGp,
|
||||
Arm64FcvtlV,
|
||||
Arm64FcvtmsS,
|
||||
Arm64FcvtmsV,
|
||||
Arm64FcvtmsGp,
|
||||
Arm64FcvtmuS,
|
||||
Arm64FcvtmuV,
|
||||
Arm64FcvtmuGp,
|
||||
Arm64FcvtnsS,
|
||||
Arm64FcvtnsV,
|
||||
Arm64FcvtnsGp,
|
||||
Arm64FcvtnuS,
|
||||
Arm64FcvtnuV,
|
||||
Arm64FcvtnuGp,
|
||||
Arm64FcvtnV,
|
||||
Arm64FcvtpsS,
|
||||
Arm64FcvtpsV,
|
||||
Arm64FcvtpsGp,
|
||||
Arm64FcvtpuS,
|
||||
Arm64FcvtpuV,
|
||||
Arm64FcvtpuGp,
|
||||
Arm64FcvtxnS,
|
||||
Arm64FcvtxnV,
|
||||
Arm64FcvtzsSFixed,
|
||||
Arm64FcvtzsVFixed,
|
||||
Arm64FcvtzsS,
|
||||
Arm64FcvtzsV,
|
||||
Arm64FcvtzsGpFixed,
|
||||
Arm64FcvtzsGp,
|
||||
Arm64FcvtzuSFixed,
|
||||
Arm64FcvtzuVFixed,
|
||||
Arm64FcvtzuS,
|
||||
Arm64FcvtzuV,
|
||||
Arm64FcvtzuGpFixed,
|
||||
Arm64FcvtzuGp,
|
||||
Arm64FcvtS,
|
||||
Arm64FdivV,
|
||||
Arm64FdivS,
|
||||
Arm64FmaddS,
|
||||
Arm64FmaxnmpS,
|
||||
Arm64FmaxnmpV,
|
||||
Arm64FmaxnmvV,
|
||||
Arm64FmaxnmV,
|
||||
Arm64FmaxnmS,
|
||||
Arm64FmaxpS,
|
||||
Arm64FmaxpV,
|
||||
Arm64FmaxvV,
|
||||
Arm64FmaxV,
|
||||
Arm64FmaxS,
|
||||
Arm64FminnmpS,
|
||||
Arm64FminnmpV,
|
||||
Arm64FminnmvV,
|
||||
Arm64FminnmV,
|
||||
Arm64FminnmS,
|
||||
Arm64FminpS,
|
||||
Arm64FminpV,
|
||||
Arm64FminvV,
|
||||
Arm64FminV,
|
||||
Arm64FminS,
|
||||
Arm64FmlaSe,
|
||||
Arm64FmlaVe,
|
||||
Arm64FmlaV,
|
||||
Arm64FmlsSe,
|
||||
Arm64FmlsVe,
|
||||
Arm64FmlsV,
|
||||
Arm64FmovVi,
|
||||
Arm64FmovS,
|
||||
Arm64FmovGp,
|
||||
Arm64FmovSi,
|
||||
Arm64FmsubS,
|
||||
Arm64FmulxSe,
|
||||
Arm64FmulxVe,
|
||||
Arm64FmulxS,
|
||||
Arm64FmulxV,
|
||||
Arm64FmulSe,
|
||||
Arm64FmulVe,
|
||||
Arm64FmulV,
|
||||
Arm64FmulS,
|
||||
Arm64FnegV,
|
||||
Arm64FnegS,
|
||||
Arm64FnmaddS,
|
||||
Arm64FnmsubS,
|
||||
Arm64FnmulS,
|
||||
Arm64FrecpeS,
|
||||
Arm64FrecpeV,
|
||||
Arm64FrecpsS,
|
||||
Arm64FrecpsV,
|
||||
Arm64FrecpxS,
|
||||
Arm64FrintaV,
|
||||
Arm64FrintaS,
|
||||
Arm64FrintiV,
|
||||
Arm64FrintiS,
|
||||
Arm64FrintmV,
|
||||
Arm64FrintmS,
|
||||
Arm64FrintnV,
|
||||
Arm64FrintnS,
|
||||
Arm64FrintpV,
|
||||
Arm64FrintpS,
|
||||
Arm64FrintxV,
|
||||
Arm64FrintxS,
|
||||
Arm64FrintzV,
|
||||
Arm64FrintzS,
|
||||
Arm64FrsqrteS,
|
||||
Arm64FrsqrteV,
|
||||
Arm64FrsqrtsS,
|
||||
Arm64FrsqrtsV,
|
||||
Arm64FsqrtV,
|
||||
Arm64FsqrtS,
|
||||
Arm64FsubV,
|
||||
Arm64FsubS,
|
||||
Arm64InsVe,
|
||||
Arm64InsGp,
|
||||
Arm64Ld1rV,
|
||||
Arm64Ld1Vms,
|
||||
Arm64Ld1Vss,
|
||||
Arm64Ld2rV,
|
||||
Arm64Ld2Vms,
|
||||
Arm64Ld2Vss,
|
||||
Arm64Ld3rV,
|
||||
Arm64Ld3Vms,
|
||||
Arm64Ld3Vss,
|
||||
Arm64Ld4rV,
|
||||
Arm64Ld4Vms,
|
||||
Arm64Ld4Vss,
|
||||
Arm64MlaVe,
|
||||
Arm64MlaV,
|
||||
Arm64MlsVe,
|
||||
Arm64MlsV,
|
||||
Arm64MoviV,
|
||||
Arm64MrsFpcr,
|
||||
Arm64MsrFpcr,
|
||||
Arm64MrsFpsr,
|
||||
Arm64MsrFpsr,
|
||||
Arm64MulVe,
|
||||
Arm64MulV,
|
||||
Arm64MvniV,
|
||||
Arm64NegS,
|
||||
Arm64NegV,
|
||||
Arm64NotV,
|
||||
Arm64OrnV,
|
||||
Arm64OrrVi,
|
||||
Arm64OrrV,
|
||||
Arm64PmullV,
|
||||
Arm64PmulV,
|
||||
Arm64RaddhnV,
|
||||
Arm64RbitV,
|
||||
Arm64Rev16V,
|
||||
Arm64Rev32V,
|
||||
Arm64Rev64V,
|
||||
Arm64RshrnV,
|
||||
Arm64RsubhnV,
|
||||
Arm64SabalV,
|
||||
Arm64SabaV,
|
||||
Arm64SabdlV,
|
||||
Arm64SabdV,
|
||||
Arm64SadalpV,
|
||||
Arm64SaddlpV,
|
||||
Arm64SaddlvV,
|
||||
Arm64SaddlV,
|
||||
Arm64SaddwV,
|
||||
Arm64ScvtfSFixed,
|
||||
Arm64ScvtfVFixed,
|
||||
Arm64ScvtfS,
|
||||
Arm64ScvtfV,
|
||||
Arm64ScvtfGpFixed,
|
||||
Arm64ScvtfGp,
|
||||
Arm64Sha1cV,
|
||||
Arm64Sha1hV,
|
||||
Arm64Sha1mV,
|
||||
Arm64Sha1pV,
|
||||
Arm64Sha1su0V,
|
||||
Arm64Sha1su1V,
|
||||
Arm64Sha256h2V,
|
||||
Arm64Sha256hV,
|
||||
Arm64Sha256su0V,
|
||||
Arm64Sha256su1V,
|
||||
Arm64ShaddV,
|
||||
Arm64ShllV,
|
||||
Arm64ShlS,
|
||||
Arm64ShlV,
|
||||
Arm64ShrnV,
|
||||
Arm64ShsubV,
|
||||
Arm64SliS,
|
||||
Arm64SliV,
|
||||
Arm64SmaxpV,
|
||||
Arm64SmaxvV,
|
||||
Arm64SmaxV,
|
||||
Arm64SminpV,
|
||||
Arm64SminvV,
|
||||
Arm64SminV,
|
||||
Arm64SmlalVe,
|
||||
Arm64SmlalV,
|
||||
Arm64SmlslVe,
|
||||
Arm64SmlslV,
|
||||
Arm64SmovV,
|
||||
Arm64SmullVe,
|
||||
Arm64SmullV,
|
||||
Arm64SqabsS,
|
||||
Arm64SqabsV,
|
||||
Arm64SqaddS,
|
||||
Arm64SqaddV,
|
||||
Arm64SqdmlalSe,
|
||||
Arm64SqdmlalVe,
|
||||
Arm64SqdmlalS,
|
||||
Arm64SqdmlalV,
|
||||
Arm64SqdmlslSe,
|
||||
Arm64SqdmlslVe,
|
||||
Arm64SqdmlslS,
|
||||
Arm64SqdmlslV,
|
||||
Arm64SqdmulhSe,
|
||||
Arm64SqdmulhVe,
|
||||
Arm64SqdmulhS,
|
||||
Arm64SqdmulhV,
|
||||
Arm64SqdmullSe,
|
||||
Arm64SqdmullVe,
|
||||
Arm64SqdmullS,
|
||||
Arm64SqdmullV,
|
||||
Arm64SqnegS,
|
||||
Arm64SqnegV,
|
||||
Arm64SqrdmulhSe,
|
||||
Arm64SqrdmulhVe,
|
||||
Arm64SqrdmulhS,
|
||||
Arm64SqrdmulhV,
|
||||
Arm64SqrshlS,
|
||||
Arm64SqrshlV,
|
||||
Arm64SqrshrnS,
|
||||
Arm64SqrshrnV,
|
||||
Arm64SqrshrunS,
|
||||
Arm64SqrshrunV,
|
||||
Arm64SqshluS,
|
||||
Arm64SqshluV,
|
||||
Arm64SqshlSi,
|
||||
Arm64SqshlVi,
|
||||
Arm64SqshlS,
|
||||
Arm64SqshlV,
|
||||
Arm64SqshrnS,
|
||||
Arm64SqshrnV,
|
||||
Arm64SqshrunS,
|
||||
Arm64SqshrunV,
|
||||
Arm64SqsubS,
|
||||
Arm64SqsubV,
|
||||
Arm64SqxtnS,
|
||||
Arm64SqxtnV,
|
||||
Arm64SqxtunS,
|
||||
Arm64SqxtunV,
|
||||
Arm64SrhaddV,
|
||||
Arm64SriS,
|
||||
Arm64SriV,
|
||||
Arm64SrshlS,
|
||||
Arm64SrshlV,
|
||||
Arm64SrshrS,
|
||||
Arm64SrshrV,
|
||||
Arm64SrsraS,
|
||||
Arm64SrsraV,
|
||||
Arm64SshllV,
|
||||
Arm64SshlS,
|
||||
Arm64SshlV,
|
||||
Arm64SshrS,
|
||||
Arm64SshrV,
|
||||
Arm64SsraS,
|
||||
Arm64SsraV,
|
||||
Arm64SsublV,
|
||||
Arm64SsubwV,
|
||||
Arm64St1Vms,
|
||||
Arm64St1Vss,
|
||||
Arm64St2Vms,
|
||||
Arm64St2Vss,
|
||||
Arm64St3Vms,
|
||||
Arm64St3Vss,
|
||||
Arm64St4Vms,
|
||||
Arm64St4Vss,
|
||||
Arm64SubhnV,
|
||||
Arm64SubS,
|
||||
Arm64SubV,
|
||||
Arm64SuqaddS,
|
||||
Arm64SuqaddV,
|
||||
Arm64TblV,
|
||||
Arm64TbxV,
|
||||
Arm64Trn1V,
|
||||
Arm64Trn2V,
|
||||
Arm64UabalV,
|
||||
Arm64UabaV,
|
||||
Arm64UabdlV,
|
||||
Arm64UabdV,
|
||||
Arm64UadalpV,
|
||||
Arm64UaddlpV,
|
||||
Arm64UaddlvV,
|
||||
Arm64UaddlV,
|
||||
Arm64UaddwV,
|
||||
Arm64UcvtfSFixed,
|
||||
Arm64UcvtfVFixed,
|
||||
Arm64UcvtfS,
|
||||
Arm64UcvtfV,
|
||||
Arm64UcvtfGpFixed,
|
||||
Arm64UcvtfGp,
|
||||
Arm64UhaddV,
|
||||
Arm64UhsubV,
|
||||
Arm64UmaxpV,
|
||||
Arm64UmaxvV,
|
||||
Arm64UmaxV,
|
||||
Arm64UminpV,
|
||||
Arm64UminvV,
|
||||
Arm64UminV,
|
||||
Arm64UmlalVe,
|
||||
Arm64UmlalV,
|
||||
Arm64UmlslVe,
|
||||
Arm64UmlslV,
|
||||
Arm64UmovV,
|
||||
Arm64UmullVe,
|
||||
Arm64UmullV,
|
||||
Arm64UqaddS,
|
||||
Arm64UqaddV,
|
||||
Arm64UqrshlS,
|
||||
Arm64UqrshlV,
|
||||
Arm64UqrshrnS,
|
||||
Arm64UqrshrnV,
|
||||
Arm64UqshlSi,
|
||||
Arm64UqshlVi,
|
||||
Arm64UqshlS,
|
||||
Arm64UqshlV,
|
||||
Arm64UqshrnS,
|
||||
Arm64UqshrnV,
|
||||
Arm64UqsubS,
|
||||
Arm64UqsubV,
|
||||
Arm64UqxtnS,
|
||||
Arm64UqxtnV,
|
||||
Arm64UrecpeV,
|
||||
Arm64UrhaddV,
|
||||
Arm64UrshlS,
|
||||
Arm64UrshlV,
|
||||
Arm64UrshrS,
|
||||
Arm64UrshrV,
|
||||
Arm64UrsqrteV,
|
||||
Arm64UrsraS,
|
||||
Arm64UrsraV,
|
||||
Arm64UshllV,
|
||||
Arm64UshlS,
|
||||
Arm64UshlV,
|
||||
Arm64UshrS,
|
||||
Arm64UshrV,
|
||||
Arm64UsqaddS,
|
||||
Arm64UsqaddV,
|
||||
Arm64UsraS,
|
||||
Arm64UsraV,
|
||||
Arm64UsublV,
|
||||
Arm64UsubwV,
|
||||
Arm64Uzp1V,
|
||||
Arm64Uzp2V,
|
||||
Arm64XtnV,
|
||||
Arm64Zip1V,
|
||||
Arm64Zip2V,
|
||||
|
||||
Arm64VTypeShift = 13,
|
||||
Arm64VTypeMask = 1 << Arm64VTypeShift,
|
||||
Arm64V64 = 0 << Arm64VTypeShift,
|
||||
Arm64V128 = 1 << Arm64VTypeShift,
|
||||
|
||||
Arm64VSizeShift = 14,
|
||||
Arm64VSizeMask = 3 << Arm64VSizeShift,
|
||||
Arm64VFloat = 0 << Arm64VSizeShift,
|
||||
Arm64VDouble = 1 << Arm64VSizeShift,
|
||||
Arm64VByte = 0 << Arm64VSizeShift,
|
||||
Arm64VHWord = 1 << Arm64VSizeShift,
|
||||
Arm64VWord = 2 << Arm64VSizeShift,
|
||||
Arm64VDWord = 3 << Arm64VSizeShift
|
||||
}
|
||||
}
|
208
src/ARMeilleure/IntermediateRepresentation/IntrusiveList.cs
Normal file
208
src/ARMeilleure/IntermediateRepresentation/IntrusiveList.cs
Normal file
|
@ -0,0 +1,208 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a efficient linked list that stores the pointer on the object directly and does not allocate.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the list items</typeparam>
|
||||
class IntrusiveList<T> where T : IEquatable<T>, IIntrusiveListNode<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// First item of the list, or null if empty.
|
||||
/// </summary>
|
||||
public T First { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Last item of the list, or null if empty.
|
||||
/// </summary>
|
||||
public T Last { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total number of items on the list.
|
||||
/// </summary>
|
||||
public int Count { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="IntrusiveList{T}"/> class.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentException"><typeparamref name="T"/> is not pointer sized.</exception>
|
||||
public IntrusiveList()
|
||||
{
|
||||
if (Unsafe.SizeOf<T>() != IntPtr.Size)
|
||||
{
|
||||
throw new ArgumentException("T must be a reference type or a pointer sized struct.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a item as the first item of the list.
|
||||
/// </summary>
|
||||
/// <param name="newNode">Item to be added</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T AddFirst(T newNode)
|
||||
{
|
||||
if (!EqualsNull(First))
|
||||
{
|
||||
return AddBefore(First, newNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(EqualsNull(newNode.ListPrevious));
|
||||
Debug.Assert(EqualsNull(newNode.ListNext));
|
||||
Debug.Assert(EqualsNull(Last));
|
||||
|
||||
First = newNode;
|
||||
Last = newNode;
|
||||
|
||||
Debug.Assert(Count == 0);
|
||||
|
||||
Count = 1;
|
||||
|
||||
return newNode;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a item as the last item of the list.
|
||||
/// </summary>
|
||||
/// <param name="newNode">Item to be added</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T AddLast(T newNode)
|
||||
{
|
||||
if (!EqualsNull(Last))
|
||||
{
|
||||
return AddAfter(Last, newNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(EqualsNull(newNode.ListPrevious));
|
||||
Debug.Assert(EqualsNull(newNode.ListNext));
|
||||
Debug.Assert(EqualsNull(First));
|
||||
|
||||
First = newNode;
|
||||
Last = newNode;
|
||||
|
||||
Debug.Assert(Count == 0);
|
||||
|
||||
Count = 1;
|
||||
|
||||
return newNode;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a item before a existing item on the list.
|
||||
/// </summary>
|
||||
/// <param name="node">Item on the list that will succeed the new item</param>
|
||||
/// <param name="newNode">Item to be added</param>
|
||||
/// <returns>New item</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T AddBefore(T node, T newNode)
|
||||
{
|
||||
Debug.Assert(EqualsNull(newNode.ListPrevious));
|
||||
Debug.Assert(EqualsNull(newNode.ListNext));
|
||||
|
||||
newNode.ListPrevious = node.ListPrevious;
|
||||
newNode.ListNext = node;
|
||||
|
||||
node.ListPrevious = newNode;
|
||||
|
||||
if (!EqualsNull(newNode.ListPrevious))
|
||||
{
|
||||
newNode.ListPrevious.ListNext = newNode;
|
||||
}
|
||||
|
||||
if (Equals(First, node))
|
||||
{
|
||||
First = newNode;
|
||||
}
|
||||
|
||||
Count++;
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a item after a existing item on the list.
|
||||
/// </summary>
|
||||
/// <param name="node">Item on the list that will preceed the new item</param>
|
||||
/// <param name="newNode">Item to be added</param>
|
||||
/// <returns>New item</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T AddAfter(T node, T newNode)
|
||||
{
|
||||
Debug.Assert(EqualsNull(newNode.ListPrevious));
|
||||
Debug.Assert(EqualsNull(newNode.ListNext));
|
||||
|
||||
newNode.ListPrevious = node;
|
||||
newNode.ListNext = node.ListNext;
|
||||
|
||||
node.ListNext = newNode;
|
||||
|
||||
if (!EqualsNull(newNode.ListNext))
|
||||
{
|
||||
newNode.ListNext.ListPrevious = newNode;
|
||||
}
|
||||
|
||||
if (Equals(Last, node))
|
||||
{
|
||||
Last = newNode;
|
||||
}
|
||||
|
||||
Count++;
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a item from the list.
|
||||
/// </summary>
|
||||
/// <param name="node">The item to be removed</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Remove(T node)
|
||||
{
|
||||
if (!EqualsNull(node.ListPrevious))
|
||||
{
|
||||
node.ListPrevious.ListNext = node.ListNext;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(Equals(First, node));
|
||||
|
||||
First = node.ListNext;
|
||||
}
|
||||
|
||||
if (!EqualsNull(node.ListNext))
|
||||
{
|
||||
node.ListNext.ListPrevious = node.ListPrevious;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(Equals(Last, node));
|
||||
|
||||
Last = node.ListPrevious;
|
||||
}
|
||||
|
||||
node.ListPrevious = default;
|
||||
node.ListNext = default;
|
||||
|
||||
Count--;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool EqualsNull(T a)
|
||||
{
|
||||
return EqualityComparer<T>.Default.Equals(a, default);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool Equals(T a, T b)
|
||||
{
|
||||
return EqualityComparer<T>.Default.Equals(a, b);
|
||||
}
|
||||
}
|
||||
}
|
54
src/ARMeilleure/IntermediateRepresentation/MemoryOperand.cs
Normal file
54
src/ARMeilleure/IntermediateRepresentation/MemoryOperand.cs
Normal file
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
unsafe struct MemoryOperand
|
||||
{
|
||||
private struct Data
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public byte Kind;
|
||||
public byte Type;
|
||||
#pragma warning restore CS0649
|
||||
public byte Scale;
|
||||
public Operand BaseAddress;
|
||||
public Operand Index;
|
||||
public int Displacement;
|
||||
}
|
||||
|
||||
private Data* _data;
|
||||
|
||||
public MemoryOperand(Operand operand)
|
||||
{
|
||||
Debug.Assert(operand.Kind == OperandKind.Memory);
|
||||
|
||||
_data = (Data*)Unsafe.As<Operand, IntPtr>(ref operand);
|
||||
}
|
||||
|
||||
public Operand BaseAddress
|
||||
{
|
||||
get => _data->BaseAddress;
|
||||
set => _data->BaseAddress = value;
|
||||
}
|
||||
|
||||
public Operand Index
|
||||
{
|
||||
get => _data->Index;
|
||||
set => _data->Index = value;
|
||||
}
|
||||
|
||||
public Multiplier Scale
|
||||
{
|
||||
get => (Multiplier)_data->Scale;
|
||||
set => _data->Scale = (byte)value;
|
||||
}
|
||||
|
||||
public int Displacement
|
||||
{
|
||||
get => _data->Displacement;
|
||||
set => _data->Displacement = value;
|
||||
}
|
||||
}
|
||||
}
|
11
src/ARMeilleure/IntermediateRepresentation/Multiplier.cs
Normal file
11
src/ARMeilleure/IntermediateRepresentation/Multiplier.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
enum Multiplier
|
||||
{
|
||||
x1 = 0,
|
||||
x2 = 1,
|
||||
x4 = 2,
|
||||
x8 = 3,
|
||||
x16 = 4
|
||||
}
|
||||
}
|
594
src/ARMeilleure/IntermediateRepresentation/Operand.cs
Normal file
594
src/ARMeilleure/IntermediateRepresentation/Operand.cs
Normal file
|
@ -0,0 +1,594 @@
|
|||
using ARMeilleure.CodeGen.Linking;
|
||||
using ARMeilleure.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
unsafe struct Operand : IEquatable<Operand>
|
||||
{
|
||||
internal struct Data
|
||||
{
|
||||
public byte Kind;
|
||||
public byte Type;
|
||||
public byte SymbolType;
|
||||
public byte Padding; // Unused space.
|
||||
public ushort AssignmentsCount;
|
||||
public ushort AssignmentsCapacity;
|
||||
public uint UsesCount;
|
||||
public uint UsesCapacity;
|
||||
public Operation* Assignments;
|
||||
public Operation* Uses;
|
||||
public ulong Value;
|
||||
public ulong SymbolValue;
|
||||
}
|
||||
|
||||
private Data* _data;
|
||||
|
||||
public OperandKind Kind
|
||||
{
|
||||
get => (OperandKind)_data->Kind;
|
||||
private set => _data->Kind = (byte)value;
|
||||
}
|
||||
|
||||
public OperandType Type
|
||||
{
|
||||
get => (OperandType)_data->Type;
|
||||
private set => _data->Type = (byte)value;
|
||||
}
|
||||
|
||||
public ulong Value
|
||||
{
|
||||
get => _data->Value;
|
||||
private set => _data->Value = value;
|
||||
}
|
||||
|
||||
public Symbol Symbol
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(Kind != OperandKind.Memory);
|
||||
|
||||
return new Symbol((SymbolType)_data->SymbolType, _data->SymbolValue);
|
||||
}
|
||||
private set
|
||||
{
|
||||
Debug.Assert(Kind != OperandKind.Memory);
|
||||
|
||||
if (value.Type == SymbolType.None)
|
||||
{
|
||||
_data->SymbolType = (byte)SymbolType.None;
|
||||
}
|
||||
else
|
||||
{
|
||||
_data->SymbolType = (byte)value.Type;
|
||||
_data->SymbolValue = value.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlySpan<Operation> Assignments
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(Kind != OperandKind.Memory);
|
||||
|
||||
return new ReadOnlySpan<Operation>(_data->Assignments, _data->AssignmentsCount);
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlySpan<Operation> Uses
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(Kind != OperandKind.Memory);
|
||||
|
||||
return new ReadOnlySpan<Operation>(_data->Uses, (int)_data->UsesCount);
|
||||
}
|
||||
}
|
||||
|
||||
public int UsesCount => (int)_data->UsesCount;
|
||||
public int AssignmentsCount => _data->AssignmentsCount;
|
||||
|
||||
public bool Relocatable => Symbol.Type != SymbolType.None;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Register GetRegister()
|
||||
{
|
||||
Debug.Assert(Kind == OperandKind.Register);
|
||||
|
||||
return new Register((int)Value & 0xffffff, (RegisterType)(Value >> 24));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MemoryOperand GetMemory()
|
||||
{
|
||||
Debug.Assert(Kind == OperandKind.Memory);
|
||||
|
||||
return new MemoryOperand(this);
|
||||
}
|
||||
|
||||
public int GetLocalNumber()
|
||||
{
|
||||
Debug.Assert(Kind == OperandKind.LocalVariable);
|
||||
|
||||
return (int)Value;
|
||||
}
|
||||
|
||||
public byte AsByte()
|
||||
{
|
||||
return (byte)Value;
|
||||
}
|
||||
|
||||
public short AsInt16()
|
||||
{
|
||||
return (short)Value;
|
||||
}
|
||||
|
||||
public int AsInt32()
|
||||
{
|
||||
return (int)Value;
|
||||
}
|
||||
|
||||
public long AsInt64()
|
||||
{
|
||||
return (long)Value;
|
||||
}
|
||||
|
||||
public float AsFloat()
|
||||
{
|
||||
return BitConverter.Int32BitsToSingle((int)Value);
|
||||
}
|
||||
|
||||
public double AsDouble()
|
||||
{
|
||||
return BitConverter.Int64BitsToDouble((long)Value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal ref ulong GetValueUnsafe()
|
||||
{
|
||||
return ref _data->Value;
|
||||
}
|
||||
|
||||
internal void NumberLocal(int number)
|
||||
{
|
||||
if (Kind != OperandKind.LocalVariable)
|
||||
{
|
||||
throw new InvalidOperationException("The operand is not a local variable.");
|
||||
}
|
||||
|
||||
Value = (ulong)number;
|
||||
}
|
||||
|
||||
public void AddAssignment(Operation operation)
|
||||
{
|
||||
if (Kind == OperandKind.LocalVariable)
|
||||
{
|
||||
Add(operation, ref _data->Assignments, ref _data->AssignmentsCount, ref _data->AssignmentsCapacity);
|
||||
}
|
||||
else if (Kind == OperandKind.Memory)
|
||||
{
|
||||
MemoryOperand memOp = GetMemory();
|
||||
Operand addr = memOp.BaseAddress;
|
||||
Operand index = memOp.Index;
|
||||
|
||||
if (addr != default)
|
||||
{
|
||||
Add(operation, ref addr._data->Assignments, ref addr._data->AssignmentsCount, ref addr._data->AssignmentsCapacity);
|
||||
}
|
||||
|
||||
if (index != default)
|
||||
{
|
||||
Add(operation, ref index._data->Assignments, ref index._data->AssignmentsCount, ref index._data->AssignmentsCapacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveAssignment(Operation operation)
|
||||
{
|
||||
if (Kind == OperandKind.LocalVariable)
|
||||
{
|
||||
Remove(operation, ref _data->Assignments, ref _data->AssignmentsCount);
|
||||
}
|
||||
else if (Kind == OperandKind.Memory)
|
||||
{
|
||||
MemoryOperand memOp = GetMemory();
|
||||
Operand addr = memOp.BaseAddress;
|
||||
Operand index = memOp.Index;
|
||||
|
||||
if (addr != default)
|
||||
{
|
||||
Remove(operation, ref addr._data->Assignments, ref addr._data->AssignmentsCount);
|
||||
}
|
||||
|
||||
if (index != default)
|
||||
{
|
||||
Remove(operation, ref index._data->Assignments, ref index._data->AssignmentsCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddUse(Operation operation)
|
||||
{
|
||||
if (Kind == OperandKind.LocalVariable)
|
||||
{
|
||||
Add(operation, ref _data->Uses, ref _data->UsesCount, ref _data->UsesCapacity);
|
||||
}
|
||||
else if (Kind == OperandKind.Memory)
|
||||
{
|
||||
MemoryOperand memOp = GetMemory();
|
||||
Operand addr = memOp.BaseAddress;
|
||||
Operand index = memOp.Index;
|
||||
|
||||
if (addr != default)
|
||||
{
|
||||
Add(operation, ref addr._data->Uses, ref addr._data->UsesCount, ref addr._data->UsesCapacity);
|
||||
}
|
||||
|
||||
if (index != default)
|
||||
{
|
||||
Add(operation, ref index._data->Uses, ref index._data->UsesCount, ref index._data->UsesCapacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveUse(Operation operation)
|
||||
{
|
||||
if (Kind == OperandKind.LocalVariable)
|
||||
{
|
||||
Remove(operation, ref _data->Uses, ref _data->UsesCount);
|
||||
}
|
||||
else if (Kind == OperandKind.Memory)
|
||||
{
|
||||
MemoryOperand memOp = GetMemory();
|
||||
Operand addr = memOp.BaseAddress;
|
||||
Operand index = memOp.Index;
|
||||
|
||||
if (addr != default)
|
||||
{
|
||||
Remove(operation, ref addr._data->Uses, ref addr._data->UsesCount);
|
||||
}
|
||||
|
||||
if (index != default)
|
||||
{
|
||||
Remove(operation, ref index._data->Uses, ref index._data->UsesCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Span<Operation> GetUses(ref Span<Operation> buffer)
|
||||
{
|
||||
ReadOnlySpan<Operation> uses = Uses;
|
||||
|
||||
if (buffer.Length < uses.Length)
|
||||
{
|
||||
buffer = Allocators.Default.AllocateSpan<Operation>((uint)uses.Length);
|
||||
}
|
||||
|
||||
uses.CopyTo(buffer);
|
||||
|
||||
return buffer.Slice(0, uses.Length);
|
||||
}
|
||||
|
||||
private static void New<T>(ref T* data, ref ushort count, ref ushort capacity, ushort initialCapacity) where T : unmanaged
|
||||
{
|
||||
count = 0;
|
||||
capacity = initialCapacity;
|
||||
data = Allocators.References.Allocate<T>(initialCapacity);
|
||||
}
|
||||
|
||||
private static void New<T>(ref T* data, ref uint count, ref uint capacity, uint initialCapacity) where T : unmanaged
|
||||
{
|
||||
count = 0;
|
||||
capacity = initialCapacity;
|
||||
data = Allocators.References.Allocate<T>(initialCapacity);
|
||||
}
|
||||
|
||||
private static void Add<T>(T item, ref T* data, ref ushort count, ref ushort capacity) where T : unmanaged
|
||||
{
|
||||
if (count < capacity)
|
||||
{
|
||||
data[(uint)count++] = item;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Could not add item in the fast path, fallback onto the slow path.
|
||||
ExpandAdd(item, ref data, ref count, ref capacity);
|
||||
|
||||
static void ExpandAdd(T item, ref T* data, ref ushort count, ref ushort capacity)
|
||||
{
|
||||
ushort newCount = checked((ushort)(count + 1));
|
||||
ushort newCapacity = (ushort)Math.Min(capacity * 2, ushort.MaxValue);
|
||||
|
||||
var oldSpan = new Span<T>(data, count);
|
||||
|
||||
capacity = newCapacity;
|
||||
data = Allocators.References.Allocate<T>(capacity);
|
||||
|
||||
oldSpan.CopyTo(new Span<T>(data, count));
|
||||
|
||||
data[count] = item;
|
||||
count = newCount;
|
||||
}
|
||||
}
|
||||
|
||||
private static void Add<T>(T item, ref T* data, ref uint count, ref uint capacity) where T : unmanaged
|
||||
{
|
||||
if (count < capacity)
|
||||
{
|
||||
data[count++] = item;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Could not add item in the fast path, fallback onto the slow path.
|
||||
ExpandAdd(item, ref data, ref count, ref capacity);
|
||||
|
||||
static void ExpandAdd(T item, ref T* data, ref uint count, ref uint capacity)
|
||||
{
|
||||
uint newCount = checked(count + 1);
|
||||
uint newCapacity = (uint)Math.Min(capacity * 2, int.MaxValue);
|
||||
|
||||
if (newCapacity <= capacity)
|
||||
{
|
||||
throw new OverflowException();
|
||||
}
|
||||
|
||||
var oldSpan = new Span<T>(data, (int)count);
|
||||
|
||||
capacity = newCapacity;
|
||||
data = Allocators.References.Allocate<T>(capacity);
|
||||
|
||||
oldSpan.CopyTo(new Span<T>(data, (int)count));
|
||||
|
||||
data[count] = item;
|
||||
count = newCount;
|
||||
}
|
||||
}
|
||||
|
||||
private static void Remove<T>(in T item, ref T* data, ref ushort count) where T : unmanaged
|
||||
{
|
||||
var span = new Span<T>(data, count);
|
||||
|
||||
for (int i = 0; i < span.Length; i++)
|
||||
{
|
||||
if (EqualityComparer<T>.Default.Equals(span[i], item))
|
||||
{
|
||||
if (i + 1 < count)
|
||||
{
|
||||
span.Slice(i + 1).CopyTo(span.Slice(i));
|
||||
}
|
||||
|
||||
count--;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void Remove<T>(in T item, ref T* data, ref uint count) where T : unmanaged
|
||||
{
|
||||
var span = new Span<T>(data, (int)count);
|
||||
|
||||
for (int i = 0; i < span.Length; i++)
|
||||
{
|
||||
if (EqualityComparer<T>.Default.Equals(span[i], item))
|
||||
{
|
||||
if (i + 1 < count)
|
||||
{
|
||||
span.Slice(i + 1).CopyTo(span.Slice(i));
|
||||
}
|
||||
|
||||
count--;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return ((ulong)_data).GetHashCode();
|
||||
}
|
||||
|
||||
public bool Equals(Operand operand)
|
||||
{
|
||||
return operand._data == _data;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Operand operand && Equals(operand);
|
||||
}
|
||||
|
||||
public static bool operator ==(Operand a, Operand b)
|
||||
{
|
||||
return a.Equals(b);
|
||||
}
|
||||
|
||||
public static bool operator !=(Operand a, Operand b)
|
||||
{
|
||||
return !a.Equals(b);
|
||||
}
|
||||
|
||||
public static class Factory
|
||||
{
|
||||
private const int InternTableSize = 256;
|
||||
private const int InternTableProbeLength = 8;
|
||||
|
||||
[ThreadStatic]
|
||||
private static Data* _internTable;
|
||||
|
||||
private static Data* InternTable
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_internTable == null)
|
||||
{
|
||||
_internTable = (Data*)NativeAllocator.Instance.Allocate((uint)sizeof(Data) * InternTableSize);
|
||||
|
||||
// Make sure the table is zeroed.
|
||||
new Span<Data>(_internTable, InternTableSize).Clear();
|
||||
}
|
||||
|
||||
return _internTable;
|
||||
}
|
||||
}
|
||||
|
||||
private static Operand Make(OperandKind kind, OperandType type, ulong value, Symbol symbol = default)
|
||||
{
|
||||
Debug.Assert(kind != OperandKind.None);
|
||||
|
||||
Data* data = null;
|
||||
|
||||
// If constant or register, then try to look up in the intern table before allocating.
|
||||
if (kind == OperandKind.Constant || kind == OperandKind.Register)
|
||||
{
|
||||
uint hash = (uint)HashCode.Combine(kind, type, value);
|
||||
|
||||
// Look in the next InternTableProbeLength slots for a match.
|
||||
for (uint i = 0; i < InternTableProbeLength; i++)
|
||||
{
|
||||
Operand interned = new();
|
||||
interned._data = &InternTable[(hash + i) % InternTableSize];
|
||||
|
||||
// If slot matches the allocation request then return that slot.
|
||||
if (interned.Kind == kind && interned.Type == type && interned.Value == value && interned.Symbol == symbol)
|
||||
{
|
||||
return interned;
|
||||
}
|
||||
// Otherwise if the slot is not occupied, we store in that slot.
|
||||
else if (interned.Kind == OperandKind.None)
|
||||
{
|
||||
data = interned._data;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we could not get a slot from the intern table, we allocate somewhere else and store there.
|
||||
if (data == null)
|
||||
{
|
||||
data = Allocators.Operands.Allocate<Data>();
|
||||
}
|
||||
|
||||
*data = default;
|
||||
|
||||
Operand result = new();
|
||||
result._data = data;
|
||||
result.Value = value;
|
||||
result.Kind = kind;
|
||||
result.Type = type;
|
||||
|
||||
if (kind != OperandKind.Memory)
|
||||
{
|
||||
result.Symbol = symbol;
|
||||
}
|
||||
|
||||
// If local variable, then the use and def list is initialized with default sizes.
|
||||
if (kind == OperandKind.LocalVariable)
|
||||
{
|
||||
New(ref result._data->Assignments, ref result._data->AssignmentsCount, ref result._data->AssignmentsCapacity, 1);
|
||||
New(ref result._data->Uses, ref result._data->UsesCount, ref result._data->UsesCapacity, 4);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Operand Const(OperandType type, long value)
|
||||
{
|
||||
Debug.Assert(type is OperandType.I32 or OperandType.I64);
|
||||
|
||||
return type == OperandType.I32 ? Const((int)value) : Const(value);
|
||||
}
|
||||
|
||||
public static Operand Const(bool value)
|
||||
{
|
||||
return Const(value ? 1 : 0);
|
||||
}
|
||||
|
||||
public static Operand Const(int value)
|
||||
{
|
||||
return Const((uint)value);
|
||||
}
|
||||
|
||||
public static Operand Const(uint value)
|
||||
{
|
||||
return Make(OperandKind.Constant, OperandType.I32, value);
|
||||
}
|
||||
|
||||
public static Operand Const(long value)
|
||||
{
|
||||
return Const(value, symbol: default);
|
||||
}
|
||||
|
||||
public static Operand Const<T>(ref T reference, Symbol symbol = default)
|
||||
{
|
||||
return Const((long)Unsafe.AsPointer(ref reference), symbol);
|
||||
}
|
||||
|
||||
public static Operand Const(long value, Symbol symbol)
|
||||
{
|
||||
return Make(OperandKind.Constant, OperandType.I64, (ulong)value, symbol);
|
||||
}
|
||||
|
||||
public static Operand Const(ulong value)
|
||||
{
|
||||
return Make(OperandKind.Constant, OperandType.I64, value);
|
||||
}
|
||||
|
||||
public static Operand ConstF(float value)
|
||||
{
|
||||
return Make(OperandKind.Constant, OperandType.FP32, (ulong)BitConverter.SingleToInt32Bits(value));
|
||||
}
|
||||
|
||||
public static Operand ConstF(double value)
|
||||
{
|
||||
return Make(OperandKind.Constant, OperandType.FP64, (ulong)BitConverter.DoubleToInt64Bits(value));
|
||||
}
|
||||
|
||||
public static Operand Label()
|
||||
{
|
||||
return Make(OperandKind.Label, OperandType.None, 0);
|
||||
}
|
||||
|
||||
public static Operand Local(OperandType type)
|
||||
{
|
||||
return Make(OperandKind.LocalVariable, type, 0);
|
||||
}
|
||||
|
||||
public static Operand Register(int index, RegisterType regType, OperandType type)
|
||||
{
|
||||
return Make(OperandKind.Register, type, (ulong)((int)regType << 24 | index));
|
||||
}
|
||||
|
||||
public static Operand Undef()
|
||||
{
|
||||
return Make(OperandKind.Undefined, OperandType.None, 0);
|
||||
}
|
||||
|
||||
public static Operand MemoryOp(
|
||||
OperandType type,
|
||||
Operand baseAddress,
|
||||
Operand index = default,
|
||||
Multiplier scale = Multiplier.x1,
|
||||
int displacement = 0)
|
||||
{
|
||||
Operand result = Make(OperandKind.Memory, type, 0);
|
||||
|
||||
MemoryOperand memory = result.GetMemory();
|
||||
memory.BaseAddress = baseAddress;
|
||||
memory.Index = index;
|
||||
memory.Scale = scale;
|
||||
memory.Displacement = displacement;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
13
src/ARMeilleure/IntermediateRepresentation/OperandKind.cs
Normal file
13
src/ARMeilleure/IntermediateRepresentation/OperandKind.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
enum OperandKind
|
||||
{
|
||||
None,
|
||||
Constant,
|
||||
Label,
|
||||
LocalVariable,
|
||||
Memory,
|
||||
Register,
|
||||
Undefined
|
||||
}
|
||||
}
|
65
src/ARMeilleure/IntermediateRepresentation/OperandType.cs
Normal file
65
src/ARMeilleure/IntermediateRepresentation/OperandType.cs
Normal file
|
@ -0,0 +1,65 @@
|
|||
using System;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
enum OperandType
|
||||
{
|
||||
None,
|
||||
I32,
|
||||
I64,
|
||||
FP32,
|
||||
FP64,
|
||||
V128
|
||||
}
|
||||
|
||||
static class OperandTypeExtensions
|
||||
{
|
||||
public static bool IsInteger(this OperandType type)
|
||||
{
|
||||
return type == OperandType.I32 ||
|
||||
type == OperandType.I64;
|
||||
}
|
||||
|
||||
public static RegisterType ToRegisterType(this OperandType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case OperandType.FP32: return RegisterType.Vector;
|
||||
case OperandType.FP64: return RegisterType.Vector;
|
||||
case OperandType.I32: return RegisterType.Integer;
|
||||
case OperandType.I64: return RegisterType.Integer;
|
||||
case OperandType.V128: return RegisterType.Vector;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Invalid operand type \"{type}\".");
|
||||
}
|
||||
|
||||
public static int GetSizeInBytes(this OperandType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case OperandType.FP32: return 4;
|
||||
case OperandType.FP64: return 8;
|
||||
case OperandType.I32: return 4;
|
||||
case OperandType.I64: return 8;
|
||||
case OperandType.V128: return 16;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Invalid operand type \"{type}\".");
|
||||
}
|
||||
|
||||
public static int GetSizeInBytesLog2(this OperandType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case OperandType.FP32: return 2;
|
||||
case OperandType.FP64: return 3;
|
||||
case OperandType.I32: return 2;
|
||||
case OperandType.I64: return 3;
|
||||
case OperandType.V128: return 4;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Invalid operand type \"{type}\".");
|
||||
}
|
||||
}
|
||||
}
|
376
src/ARMeilleure/IntermediateRepresentation/Operation.cs
Normal file
376
src/ARMeilleure/IntermediateRepresentation/Operation.cs
Normal file
|
@ -0,0 +1,376 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
unsafe struct Operation : IEquatable<Operation>, IIntrusiveListNode<Operation>
|
||||
{
|
||||
internal struct Data
|
||||
{
|
||||
public ushort Instruction;
|
||||
public ushort Intrinsic;
|
||||
public ushort SourcesCount;
|
||||
public ushort DestinationsCount;
|
||||
public Operation ListPrevious;
|
||||
public Operation ListNext;
|
||||
public Operand* Destinations;
|
||||
public Operand* Sources;
|
||||
}
|
||||
|
||||
private Data* _data;
|
||||
|
||||
public Instruction Instruction
|
||||
{
|
||||
get => (Instruction)_data->Instruction;
|
||||
private set => _data->Instruction = (ushort)value;
|
||||
}
|
||||
|
||||
public Intrinsic Intrinsic
|
||||
{
|
||||
get => (Intrinsic)_data->Intrinsic;
|
||||
private set => _data->Intrinsic = (ushort)value;
|
||||
}
|
||||
|
||||
public Operation ListPrevious
|
||||
{
|
||||
get => _data->ListPrevious;
|
||||
set => _data->ListPrevious = value;
|
||||
}
|
||||
|
||||
public Operation ListNext
|
||||
{
|
||||
get => _data->ListNext;
|
||||
set => _data->ListNext = value;
|
||||
}
|
||||
|
||||
public Operand Destination
|
||||
{
|
||||
get => _data->DestinationsCount != 0 ? GetDestination(0) : default;
|
||||
set => SetDestination(value);
|
||||
}
|
||||
|
||||
public int DestinationsCount => _data->DestinationsCount;
|
||||
public int SourcesCount => _data->SourcesCount;
|
||||
|
||||
internal Span<Operand> DestinationsUnsafe => new(_data->Destinations, _data->DestinationsCount);
|
||||
internal Span<Operand> SourcesUnsafe => new(_data->Sources, _data->SourcesCount);
|
||||
|
||||
public PhiOperation AsPhi()
|
||||
{
|
||||
Debug.Assert(Instruction == Instruction.Phi);
|
||||
|
||||
return new PhiOperation(this);
|
||||
}
|
||||
|
||||
public Operand GetDestination(int index)
|
||||
{
|
||||
return DestinationsUnsafe[index];
|
||||
}
|
||||
|
||||
public Operand GetSource(int index)
|
||||
{
|
||||
return SourcesUnsafe[index];
|
||||
}
|
||||
|
||||
public void SetDestination(int index, Operand dest)
|
||||
{
|
||||
ref Operand curDest = ref DestinationsUnsafe[index];
|
||||
|
||||
RemoveAssignment(curDest);
|
||||
AddAssignment(dest);
|
||||
|
||||
curDest = dest;
|
||||
}
|
||||
|
||||
public void SetSource(int index, Operand src)
|
||||
{
|
||||
ref Operand curSrc = ref SourcesUnsafe[index];
|
||||
|
||||
RemoveUse(curSrc);
|
||||
AddUse(src);
|
||||
|
||||
curSrc = src;
|
||||
}
|
||||
|
||||
private void RemoveOldDestinations()
|
||||
{
|
||||
for (int i = 0; i < _data->DestinationsCount; i++)
|
||||
{
|
||||
RemoveAssignment(_data->Destinations[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDestination(Operand dest)
|
||||
{
|
||||
RemoveOldDestinations();
|
||||
|
||||
if (dest == default)
|
||||
{
|
||||
_data->DestinationsCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
EnsureCapacity(ref _data->Destinations, ref _data->DestinationsCount, 1);
|
||||
|
||||
_data->Destinations[0] = dest;
|
||||
|
||||
AddAssignment(dest);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDestinations(Operand[] dests)
|
||||
{
|
||||
RemoveOldDestinations();
|
||||
|
||||
EnsureCapacity(ref _data->Destinations, ref _data->DestinationsCount, dests.Length);
|
||||
|
||||
for (int index = 0; index < dests.Length; index++)
|
||||
{
|
||||
Operand newOp = dests[index];
|
||||
|
||||
_data->Destinations[index] = newOp;
|
||||
|
||||
AddAssignment(newOp);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveOldSources()
|
||||
{
|
||||
for (int index = 0; index < _data->SourcesCount; index++)
|
||||
{
|
||||
RemoveUse(_data->Sources[index]);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSource(Operand src)
|
||||
{
|
||||
RemoveOldSources();
|
||||
|
||||
if (src == default)
|
||||
{
|
||||
_data->SourcesCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
EnsureCapacity(ref _data->Sources, ref _data->SourcesCount, 1);
|
||||
|
||||
_data->Sources[0] = src;
|
||||
|
||||
AddUse(src);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSources(Operand[] srcs)
|
||||
{
|
||||
RemoveOldSources();
|
||||
|
||||
EnsureCapacity(ref _data->Sources, ref _data->SourcesCount, srcs.Length);
|
||||
|
||||
for (int index = 0; index < srcs.Length; index++)
|
||||
{
|
||||
Operand newOp = srcs[index];
|
||||
|
||||
_data->Sources[index] = newOp;
|
||||
|
||||
AddUse(newOp);
|
||||
}
|
||||
}
|
||||
|
||||
public void TurnIntoCopy(Operand source)
|
||||
{
|
||||
Instruction = Instruction.Copy;
|
||||
|
||||
SetSource(source);
|
||||
}
|
||||
|
||||
private void AddAssignment(Operand op)
|
||||
{
|
||||
if (op != default)
|
||||
{
|
||||
op.AddAssignment(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveAssignment(Operand op)
|
||||
{
|
||||
if (op != default)
|
||||
{
|
||||
op.RemoveAssignment(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddUse(Operand op)
|
||||
{
|
||||
if (op != default)
|
||||
{
|
||||
op.AddUse(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveUse(Operand op)
|
||||
{
|
||||
if (op != default)
|
||||
{
|
||||
op.RemoveUse(this);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(Operation operation)
|
||||
{
|
||||
return operation._data == _data;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Operation operation && Equals(operation);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine((IntPtr)_data);
|
||||
}
|
||||
|
||||
public static bool operator ==(Operation a, Operation b)
|
||||
{
|
||||
return a.Equals(b);
|
||||
}
|
||||
|
||||
public static bool operator !=(Operation a, Operation b)
|
||||
{
|
||||
return !a.Equals(b);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void EnsureCapacity(ref Operand* list, ref ushort capacity, int newCapacity)
|
||||
{
|
||||
if (newCapacity > ushort.MaxValue)
|
||||
{
|
||||
ThrowOverflow(newCapacity);
|
||||
}
|
||||
// We only need to allocate a new buffer if we're increasing the size.
|
||||
else if (newCapacity > capacity)
|
||||
{
|
||||
list = Allocators.References.Allocate<Operand>((uint)newCapacity);
|
||||
}
|
||||
|
||||
capacity = (ushort)newCapacity;
|
||||
}
|
||||
|
||||
private static void ThrowOverflow(int count) =>
|
||||
throw new OverflowException($"Exceeded maximum size for Source or Destinations. Required {count}.");
|
||||
|
||||
public static class Factory
|
||||
{
|
||||
private static Operation Make(Instruction inst, int destCount, int srcCount)
|
||||
{
|
||||
Data* data = Allocators.Operations.Allocate<Data>();
|
||||
*data = default;
|
||||
|
||||
Operation result = new();
|
||||
result._data = data;
|
||||
result.Instruction = inst;
|
||||
|
||||
EnsureCapacity(ref result._data->Destinations, ref result._data->DestinationsCount, destCount);
|
||||
EnsureCapacity(ref result._data->Sources, ref result._data->SourcesCount, srcCount);
|
||||
|
||||
result.DestinationsUnsafe.Clear();
|
||||
result.SourcesUnsafe.Clear();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Operation Operation(Instruction inst, Operand dest)
|
||||
{
|
||||
Operation result = Make(inst, 0, 0);
|
||||
result.SetDestination(dest);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Operation Operation(Instruction inst, Operand dest, Operand src0)
|
||||
{
|
||||
Operation result = Make(inst, 0, 1);
|
||||
result.SetDestination(dest);
|
||||
result.SetSource(0, src0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Operation Operation(Instruction inst, Operand dest, Operand src0, Operand src1)
|
||||
{
|
||||
Operation result = Make(inst, 0, 2);
|
||||
result.SetDestination(dest);
|
||||
result.SetSource(0, src0);
|
||||
result.SetSource(1, src1);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Operation Operation(Instruction inst, Operand dest, Operand src0, Operand src1, Operand src2)
|
||||
{
|
||||
Operation result = Make(inst, 0, 3);
|
||||
result.SetDestination(dest);
|
||||
result.SetSource(0, src0);
|
||||
result.SetSource(1, src1);
|
||||
result.SetSource(2, src2);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Operation Operation(Instruction inst, Operand dest, int srcCount)
|
||||
{
|
||||
Operation result = Make(inst, 0, srcCount);
|
||||
result.SetDestination(dest);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Operation Operation(Instruction inst, Operand dest, Operand[] srcs)
|
||||
{
|
||||
Operation result = Make(inst, 0, srcs.Length);
|
||||
|
||||
result.SetDestination(dest);
|
||||
|
||||
for (int index = 0; index < srcs.Length; index++)
|
||||
{
|
||||
result.SetSource(index, srcs[index]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Operation Operation(Intrinsic intrin, Operand dest, params Operand[] srcs)
|
||||
{
|
||||
Operation result = Make(Instruction.Extended, 0, srcs.Length);
|
||||
|
||||
result.Intrinsic = intrin;
|
||||
result.SetDestination(dest);
|
||||
|
||||
for (int index = 0; index < srcs.Length; index++)
|
||||
{
|
||||
result.SetSource(index, srcs[index]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Operation Operation(Instruction inst, Operand[] dests, Operand[] srcs)
|
||||
{
|
||||
Operation result = Make(inst, dests.Length, srcs.Length);
|
||||
|
||||
for (int index = 0; index < dests.Length; index++)
|
||||
{
|
||||
result.SetDestination(index, dests[index]);
|
||||
}
|
||||
|
||||
for (int index = 0; index < srcs.Length; index++)
|
||||
{
|
||||
result.SetSource(index, srcs[index]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Operation PhiOperation(Operand dest, int srcCount)
|
||||
{
|
||||
return Operation(Instruction.Phi, dest, srcCount * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
37
src/ARMeilleure/IntermediateRepresentation/PhiOperation.cs
Normal file
37
src/ARMeilleure/IntermediateRepresentation/PhiOperation.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
using ARMeilleure.Translation;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
readonly struct PhiOperation
|
||||
{
|
||||
private readonly Operation _operation;
|
||||
|
||||
public PhiOperation(Operation operation)
|
||||
{
|
||||
_operation = operation;
|
||||
}
|
||||
|
||||
public int SourcesCount => _operation.SourcesCount / 2;
|
||||
|
||||
public BasicBlock GetBlock(ControlFlowGraph cfg, int index)
|
||||
{
|
||||
return cfg.PostOrderBlocks[cfg.PostOrderMap[_operation.GetSource(index * 2).AsInt32()]];
|
||||
}
|
||||
|
||||
public void SetBlock(int index, BasicBlock block)
|
||||
{
|
||||
_operation.SetSource(index * 2, Const(block.Index));
|
||||
}
|
||||
|
||||
public Operand GetSource(int index)
|
||||
{
|
||||
return _operation.GetSource(index * 2 + 1);
|
||||
}
|
||||
|
||||
public void SetSource(int index, Operand operand)
|
||||
{
|
||||
_operation.SetSource(index * 2 + 1, operand);
|
||||
}
|
||||
}
|
||||
}
|
43
src/ARMeilleure/IntermediateRepresentation/Register.cs
Normal file
43
src/ARMeilleure/IntermediateRepresentation/Register.cs
Normal file
|
@ -0,0 +1,43 @@
|
|||
using System;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
readonly struct Register : IEquatable<Register>
|
||||
{
|
||||
public int Index { get; }
|
||||
|
||||
public RegisterType Type { get; }
|
||||
|
||||
public Register(int index, RegisterType type)
|
||||
{
|
||||
Index = index;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (ushort)Index | ((int)Type << 16);
|
||||
}
|
||||
|
||||
public static bool operator ==(Register x, Register y)
|
||||
{
|
||||
return x.Equals(y);
|
||||
}
|
||||
|
||||
public static bool operator !=(Register x, Register y)
|
||||
{
|
||||
return !x.Equals(y);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Register reg && Equals(reg);
|
||||
}
|
||||
|
||||
public bool Equals(Register other)
|
||||
{
|
||||
return other.Index == Index &&
|
||||
other.Type == Type;
|
||||
}
|
||||
}
|
||||
}
|
10
src/ARMeilleure/IntermediateRepresentation/RegisterType.cs
Normal file
10
src/ARMeilleure/IntermediateRepresentation/RegisterType.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
enum RegisterType
|
||||
{
|
||||
Integer,
|
||||
Vector,
|
||||
Flag,
|
||||
FpFlag
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue