| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.IO;
- namespace Spv.Generator
- {
- public sealed class Instruction : Operand, IEquatable<Instruction>
- {
- public const uint InvalidId = uint.MaxValue;
- public Specification.Op Opcode { get; private set; }
- private Instruction _resultType;
- private InstructionOperands _operands;
- public uint Id { get; set; }
- public Instruction() { }
- public void Set(Specification.Op opcode, uint id = InvalidId, Instruction resultType = null)
- {
- Opcode = opcode;
- Id = id;
- _resultType = resultType;
- _operands = new InstructionOperands();
- }
- public void SetId(uint id)
- {
- Id = id;
- }
- public OperandType Type => OperandType.Instruction;
- public ushort GetTotalWordCount()
- {
- ushort result = WordCount;
- if (Id != InvalidId)
- {
- result++;
- }
- if (_resultType != null)
- {
- result += _resultType.WordCount;
- }
- Span<Operand> operands = _operands.AsSpan();
- for (int i = 0; i < operands.Length; i++)
- {
- result += operands[i].WordCount;
- }
- return result;
- }
- public ushort WordCount => 1;
- public void AddOperand(Operand value)
- {
- Debug.Assert(value != null);
- _operands.Add(value);
- }
- public void AddOperand(Operand[] value)
- {
- foreach (Operand instruction in value)
- {
- AddOperand(instruction);
- }
- }
- public void AddOperand(LiteralInteger[] value)
- {
- foreach (LiteralInteger instruction in value)
- {
- AddOperand(instruction);
- }
- }
- public void AddOperand(LiteralInteger value)
- {
- AddOperand((Operand)value);
- }
- public void AddOperand(Instruction[] value)
- {
- foreach (Instruction instruction in value)
- {
- AddOperand(instruction);
- }
- }
- public void AddOperand(Instruction value)
- {
- AddOperand((Operand)value);
- }
- public void AddOperand(string value)
- {
- AddOperand(new LiteralString(value));
- }
- public void AddOperand<T>(T value) where T: Enum
- {
- AddOperand(LiteralInteger.CreateForEnum(value));
- }
- public void Write(BinaryWriter writer)
- {
- // Word 0
- writer.Write((ushort)Opcode);
- writer.Write(GetTotalWordCount());
- _resultType?.WriteOperand(writer);
- if (Id != InvalidId)
- {
- writer.Write(Id);
- }
- Span<Operand> operands = _operands.AsSpan();
- for (int i = 0; i < operands.Length; i++)
- {
- operands[i].WriteOperand(writer);
- }
- }
- public void WriteOperand(BinaryWriter writer)
- {
- Debug.Assert(Id != InvalidId);
- if (Id == InvalidId)
- {
- string methodToCall;
- if (Opcode == Specification.Op.OpVariable)
- {
- methodToCall = "AddLocalVariable or AddGlobalVariable";
- }
- else if (Opcode == Specification.Op.OpLabel)
- {
- methodToCall = "AddLabel";
- }
- else
- {
- throw new InvalidOperationException("Internal error");
- }
- throw new InvalidOperationException($"Id wasn't bound to the module, please make sure to call {methodToCall}");
- }
- writer.Write(Id);
- }
- public override bool Equals(object obj)
- {
- return obj is Instruction instruction && Equals(instruction);
- }
- public bool Equals(Instruction cmpObj)
- {
- bool result = Type == cmpObj.Type && Id == cmpObj.Id;
- if (result)
- {
- if (_resultType != null && cmpObj._resultType != null)
- {
- result &= _resultType.Equals(cmpObj._resultType);
- }
- else if (_resultType != null || cmpObj._resultType != null)
- {
- return false;
- }
- }
- if (result)
- {
- result &= EqualsContent(cmpObj);
- }
- return result;
- }
- public bool EqualsContent(Instruction cmpObj)
- {
- Span<Operand> thisOperands = _operands.AsSpan();
- Span<Operand> cmpOperands = cmpObj._operands.AsSpan();
- if (thisOperands.Length != cmpOperands.Length)
- {
- return false;
- }
- for (int i = 0; i < thisOperands.Length; i++)
- {
- if (!thisOperands[i].Equals(cmpOperands[i]))
- {
- return false;
- }
- }
- return true;
- }
- public bool EqualsResultType(Instruction cmpObj)
- {
- return _resultType.Opcode == cmpObj._resultType.Opcode && _resultType.EqualsContent(cmpObj._resultType);
- }
- public int GetHashCodeContent()
- {
- return DeterministicHashCode.Combine<Operand>(_operands.AsSpan());
- }
- public int GetHashCodeResultType()
- {
- return DeterministicHashCode.Combine(_resultType.Opcode, _resultType.GetHashCodeContent());
- }
- public override int GetHashCode()
- {
- return DeterministicHashCode.Combine(Opcode, Id, _resultType, DeterministicHashCode.Combine<Operand>(_operands.AsSpan()));
- }
- public bool Equals(Operand obj)
- {
- return obj is Instruction instruction && Equals(instruction);
- }
-
- private static readonly Dictionary<Specification.Op, string[]> _operandLabels = new()
- {
- { Specification.Op.OpConstant, new [] { "Value" } },
- { Specification.Op.OpTypeInt, new [] { "Width", "Signed" } },
- { Specification.Op.OpTypeFloat, new [] { "Width" } }
- };
- public override string ToString()
- {
- var labels = _operandLabels.TryGetValue(Opcode, out var opLabels) ? opLabels : Array.Empty<string>();
- var result = _resultType == null ? string.Empty : $"{_resultType} ";
- return $"{result}{Opcode}{_operands.ToString(labels)}";
- }
- }
- }
|