public static Module ReadFrom(Stream stream) { BinaryReader br = new BinaryReader(stream); Reader reader = new Reader(br); uint versionNumber = reader.ReadDWord(); int majorVersion = (int)(versionNumber >> 16); int minorVersion = (int)((versionNumber >> 8) & 0xFF); Version version = new Version(majorVersion, minorVersion); uint generatorMagicNumber = reader.ReadDWord(); int generatorToolId = (int)(generatorMagicNumber >> 16); string generatorVendor = "unknown"; string generatorName = null; if (Meta.Tools.ContainsKey(generatorToolId)) { Meta.ToolInfo toolInfo = Meta.Tools[generatorToolId]; generatorVendor = toolInfo.Vendor; if (toolInfo.Name != null) { generatorName = toolInfo.Name; } } // Read header ModuleHeader header = new ModuleHeader(); header.Version = version; header.GeneratorName = generatorName; header.GeneratorVendor = generatorVendor; header.GeneratorVersion = (int)(generatorMagicNumber & 0xFFFF); header.Bound = reader.ReadDWord(); header.Reserved = reader.ReadDWord(); List <ParsedInstruction> instructions = new List <ParsedInstruction>(); while (!reader.EndOfStream) { uint instructionStart = reader.ReadDWord(); ushort wordCount = (ushort)(instructionStart >> 16); int opCode = (int)(instructionStart & 0xFFFF); uint[] words = new uint[wordCount]; words[0] = instructionStart; for (ushort i = 1; i < wordCount; ++i) { words[i] = reader.ReadDWord(); } ParsedInstruction instruction = new ParsedInstruction(opCode, words); instructions.Add(instruction); } return(new Module(header, instructions)); }
private static void PrintInstruction(StringBuilder sb, ParsedInstruction instruction, DisassemblyOptions options) { if (instruction.Operands.Count == 0) { sb.Append(instruction.Instruction.Name); return; } int currentOperand = 0; if (instruction.Instruction.Operands[currentOperand].Type is IdResultType) { if (options.HasFlag(DisassemblyOptions.ShowTypes)) { sb.Append(instruction.ResultType.ToString()); sb.Append(" "); } ++currentOperand; } if (currentOperand < instruction.Operands.Count && instruction.Instruction.Operands[currentOperand].Type is IdResult) { if (!options.HasFlag(DisassemblyOptions.ShowNames) || string.IsNullOrWhiteSpace(instruction.Name)) { PrintOperandValue(sb, instruction.Operands[currentOperand].Value, options); } else { sb.Append(instruction.Name); } sb.Append(" = "); ++currentOperand; } sb.Append(instruction.Instruction.Name); sb.Append(" "); for (; currentOperand < instruction.Operands.Count; ++currentOperand) { PrintOperandValue(sb, instruction.Operands[currentOperand].Value, options); sb.Append(" "); } }
private static void Read(IReadOnlyList <ParsedInstruction> instructions, Dictionary <uint, ParsedInstruction> objects) { // Debug instructions can be only processed after everything // else has been parsed, as they may reference types which haven't // been seen in the file yet List <ParsedInstruction> debugInstructions = new List <ParsedInstruction>(); // Entry points contain forward references // Those need to be resolved afterwards List <ParsedInstruction> entryPoints = new List <ParsedInstruction>(); foreach (var instruction in instructions) { if (IsDebugInstruction(instruction)) { debugInstructions.Add(instruction); continue; } if (instruction.Instruction is OpEntryPoint) { entryPoints.Add(instruction); continue; } if (instruction.Instruction.Name.StartsWith("OpType", StringComparison.Ordinal)) { ProcessTypeInstruction(instruction, objects); } instruction.ResolveResultType(objects); if (instruction.HasResult) { objects[instruction.ResultId] = instruction; } switch (instruction.Instruction) { // Constants require that the result type has been resolved case OpSpecConstant sc: case OpConstant oc: { Type t = instruction.ResultType; Debug.Assert(t != null); Debug.Assert(t is ScalarType); object constant = ConvertConstant(instruction.ResultType as ScalarType, instruction.Words, 3); instruction.Operands[2].Value = constant; instruction.Value = constant; } break; } } foreach (ParsedInstruction instruction in debugInstructions) { switch (instruction.Instruction) { case OpMemberName mn: { StructType t = (StructType)objects[instruction.Words[1]].ResultType; t.SetMemberName((uint)instruction.Operands[1].Value, (string)instruction.Operands[2].Value); } break; case OpName n: { // We skip naming objects we don't know about ParsedInstruction t = objects[instruction.Words[1]]; t.Name = (string)instruction.Operands[1].Value; } break; } } foreach (ParsedInstruction instruction in instructions) { instruction.ResolveReferences(objects); } }
public static bool IsDebugInstruction(ParsedInstruction instruction) { return(debugInstructions_.Contains(instruction.Instruction.Name)); }
/// <summary> /// Collect types from OpType* instructions /// </summary> private static void ProcessTypeInstruction(ParsedInstruction i, IReadOnlyDictionary <uint, ParsedInstruction> objects) { switch (i.Instruction) { case OpTypeInt t: { i.ResultType = new IntegerType((int)i.Words[2], i.Words[3] == 1u); } break; case OpTypeFloat t: { i.ResultType = new FloatingPointType((int)i.Words[2]); } break; case OpTypeVector t: { i.ResultType = new VectorType((ScalarType)objects[i.Words[2]].ResultType, (int)i.Words[3]); } break; case OpTypeMatrix t: { i.ResultType = new MatrixType((VectorType)objects[i.Words[2]].ResultType, (int)i.Words[3]); } break; case OpTypeArray t: { object constant = objects[i.Words[3]].Value; int size = 0; switch (constant) { case ushort u16: size = u16; break; case uint u32: size = (int)u32; break; case ulong u64: size = (int)u64; break; case short i16: size = i16; break; case int i32: size = i32; break; case long i64: size = (int)i64; break; } i.ResultType = new ArrayType(objects[i.Words[2]].ResultType, size); } break; case OpTypeRuntimeArray t: { i.ResultType = new RuntimeArrayType((Type)objects[i.Words[2]].ResultType); } break; case OpTypeBool t: { i.ResultType = new BoolType(); } break; case OpTypeOpaque t: { i.ResultType = new OpaqueType(); } break; case OpTypeVoid t: { i.ResultType = new VoidType(); } break; case OpTypeImage t: { Type sampledType = objects[i.Operands[1].GetId()].ResultType; Dim dim = i.Operands[2].GetSingleEnumValue <Dim>(); uint depth = (uint)i.Operands[3].Value; bool isArray = (uint)i.Operands[4].Value != 0; bool isMultiSampled = (uint)i.Operands[5].Value != 0; uint sampled = (uint)i.Operands[6].Value; ImageFormat imageFormat = i.Operands[7].GetSingleEnumValue <ImageFormat>(); i.ResultType = new ImageType(sampledType, dim, (int)depth, isArray, isMultiSampled, (int)sampled, imageFormat, i.Operands.Count > 8 ? i.Operands[8].GetSingleEnumValue <AccessQualifier>() : AccessQualifier.ReadOnly); } break; case OpTypeSampler st: { i.ResultType = new SamplerType(); break; } case OpTypeSampledImage t: { i.ResultType = new SampledImageType((ImageType)objects[i.Words[2]].ResultType); } break; case OpTypeFunction t: { List <Type> parameterTypes = new List <Type>(); for (int j = 3; j < i.Words.Count; ++j) { parameterTypes.Add(objects[i.Words[j]].ResultType); } i.ResultType = new FunctionType(objects[i.Words[2]].ResultType, parameterTypes); } break; case OpTypeForwardPointer t: { // We create a normal pointer, but with unspecified type // This will get resolved later on i.ResultType = new PointerType((StorageClass)i.Words[2]); } break; case OpTypePointer t: { if (objects.ContainsKey(i.Words[1])) { // If there is something present, it must have been // a forward reference. The storage type must // match PointerType pt = (PointerType)i.ResultType; Debug.Assert(pt != null); Debug.Assert(pt.StorageClass == (StorageClass)i.Words[2]); pt.ResolveForwardReference(objects[i.Words[3]].ResultType); } else { i.ResultType = new PointerType((StorageClass)i.Words[2], objects[i.Words[3]].ResultType); } } break; case OpTypeStruct t: { List <Type> memberTypes = new List <Type>(); for (int j = 2; j < i.Words.Count; ++j) { memberTypes.Add(objects[i.Words[j]].ResultType); } i.ResultType = new StructType(memberTypes); } break; } }
public string Disassemble(Module module, DisassemblyOptions options) { m_sb.AppendLine("; SPIR-V"); m_sb.Append("; Version: ").Append(module.Header.Version).AppendLine(); if (module.Header.GeneratorName == null) { m_sb.Append("; Generator: unknown; ").Append(module.Header.GeneratorVersion).AppendLine(); } else { m_sb.Append("; Generator: ").Append(module.Header.GeneratorVendor).Append(' '). Append(module.Header.GeneratorName).Append("; ").Append(module.Header.GeneratorVersion).AppendLine(); } m_sb.Append("; Bound: ").Append(module.Header.Bound).AppendLine(); m_sb.Append("; Schema: ").Append(module.Header.Reserved).AppendLine(); string[] lines = new string[module.Instructions.Count + 1]; lines[0] = m_sb.ToString(); m_sb.Clear(); for (int i = 0; i < module.Instructions.Count; i++) { ParsedInstruction instruction = module.Instructions[i]; PrintInstruction(m_sb, instruction, options); lines[i + 1] = m_sb.ToString(); m_sb.Clear(); } int longestPrefix = 0; for (int i = 0; i < lines.Length; i++) { string line = lines[i]; longestPrefix = Math.Max(longestPrefix, line.IndexOf('=')); if (longestPrefix > 50) { longestPrefix = 50; break; } } m_sb.Append(lines[0]); for (int i = 1; i < lines.Length; i++) { string line = lines[i]; int index = line.IndexOf('='); if (index == -1) { m_sb.Append(' ', longestPrefix + 4); m_sb.Append(line); } else { int pad = Math.Max(0, longestPrefix - index); m_sb.Append(' ', pad); m_sb.Append(line, 0, index); m_sb.Append('='); m_sb.Append(line, index + 1, line.Length - index - 1); } m_sb.AppendLine(); } string result = m_sb.ToString(); m_sb.Clear(); return(result); }