diff options
Diffstat (limited to 'ARMeilleure/IntermediateRepresentation/Operation.cs')
-rw-r--r-- | ARMeilleure/IntermediateRepresentation/Operation.cs | 384 |
1 files changed, 332 insertions, 52 deletions
diff --git a/ARMeilleure/IntermediateRepresentation/Operation.cs b/ARMeilleure/IntermediateRepresentation/Operation.cs index 4cdbe326..08b874cf 100644 --- a/ARMeilleure/IntermediateRepresentation/Operation.cs +++ b/ARMeilleure/IntermediateRepresentation/Operation.cs @@ -1,89 +1,180 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; + namespace ARMeilleure.IntermediateRepresentation { - class Operation : Node + unsafe struct Operation : IEquatable<Operation>, IIntrusiveListNode<Operation> { - public Instruction Instruction { get; private set; } + 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; + } - public Operation() : base() { } + private Data* _data; - public Operation( - Instruction instruction, - Operand destination, - Operand[] sources) : base(destination, sources.Length) + public Instruction Instruction { - Instruction = instruction; + get => (Instruction)_data->Instruction; + private set => _data->Instruction = (ushort)value; + } - for (int index = 0; index < sources.Length; index++) - { - SetSource(index, sources[index]); - } + public Intrinsic Intrinsic + { + get => (Intrinsic)_data->Intrinsic; + private set => _data->Intrinsic = (ushort)value; } - public Operation With(Instruction instruction, Operand destination) + public Operation ListPrevious { - With(destination, 0); - Instruction = instruction; - return this; + get => _data->ListPrevious; + set => _data->ListPrevious = value; } - public Operation With(Instruction instruction, Operand destination, Operand[] sources) + public Operation ListNext { - With(destination, sources.Length); - Instruction = instruction; + get => _data->ListNext; + set => _data->ListNext = value; + } - for (int index = 0; index < sources.Length; index++) + public Operand Destination + { + get => _data->DestinationsCount != 0 ? GetDestination(0) : default; + set => SetDestination(value); + } + + public int DestinationsCount => _data->DestinationsCount; + public int SourcesCount => _data->SourcesCount; + + private Span<Operand> Destinations => new(_data->Destinations, _data->DestinationsCount); + private Span<Operand> Sources => new(_data->Sources, _data->SourcesCount); + + public PhiOperation AsPhi() + { + Debug.Assert(Instruction == Instruction.Phi); + + return new PhiOperation(this); + } + + public Operand GetDestination(int index) + { + return Destinations[index]; + } + + public Operand GetSource(int index) + { + return Sources[index]; + } + + public void SetDestination(int index, Operand dest) + { + ref Operand curDest = ref Destinations[index]; + + RemoveAssignment(curDest); + AddAssignment(dest); + + curDest = dest; + } + + public void SetSource(int index, Operand src) + { + ref Operand curSrc = ref Sources[index]; + + RemoveUse(curSrc); + AddUse(src); + + curSrc = src; + } + + private void RemoveOldDestinations() + { + for (int i = 0; i < _data->DestinationsCount; i++) { - SetSource(index, sources[index]); + RemoveAssignment(_data->Destinations[i]); } - return this; } - public Operation With(Instruction instruction, Operand destination, - Operand source0) + public void SetDestination(Operand dest) { - With(destination, 1); - Instruction = instruction; + RemoveOldDestinations(); + + if (dest == default) + { + _data->DestinationsCount = 0; + } + else + { + EnsureCapacity(ref _data->Destinations, ref _data->DestinationsCount, 1); + + _data->Destinations[0] = dest; - SetSource(0, source0); - return this; + AddAssignment(dest); + } } - public Operation With(Instruction instruction, Operand destination, - Operand source0, Operand source1) + public void SetDestinations(Operand[] dests) { - With(destination, 2); - Instruction = instruction; + 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; - SetSource(0, source0); - SetSource(1, source1); - return this; + AddAssignment(newOp); + } } - public Operation With(Instruction instruction, Operand destination, - Operand source0, Operand source1, Operand source2) + private void RemoveOldSources() { - With(destination, 3); - Instruction = instruction; + for (int index = 0; index < _data->SourcesCount; index++) + { + RemoveUse(_data->Sources[index]); + } + } + + public void SetSource(Operand src) + { + RemoveOldSources(); - SetSource(0, source0); - SetSource(1, source1); - SetSource(2, source2); - return this; + if (src == default) + { + _data->SourcesCount = 0; + } + else + { + EnsureCapacity(ref _data->Sources, ref _data->SourcesCount, 1); + + _data->Sources[0] = src; + + AddUse(src); + } } - public Operation With( - Instruction instruction, - Operand[] destinations, - Operand[] sources) + public void SetSources(Operand[] srcs) { - With(destinations, sources.Length); - Instruction = instruction; + RemoveOldSources(); - for (int index = 0; index < sources.Length; index++) + EnsureCapacity(ref _data->Sources, ref _data->SourcesCount, srcs.Length); + + for (int index = 0; index < srcs.Length; index++) { - SetSource(index, sources[index]); + Operand newOp = srcs[index]; + + _data->Sources[index] = newOp; + + AddUse(newOp); } - return this; } public void TurnIntoCopy(Operand source) @@ -92,5 +183,194 @@ namespace ARMeilleure.IntermediateRepresentation 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.Destinations.Clear(); + result.Sources.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); + } + } } }
\ No newline at end of file |