Beispiel #1
0
        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));
        }
Beispiel #2
0
        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(" ");
            }
        }
Beispiel #3
0
        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);
            }
        }
Beispiel #4
0
 public static bool IsDebugInstruction(ParsedInstruction instruction)
 {
     return(debugInstructions_.Contains(instruction.Instruction.Name));
 }
Beispiel #5
0
        /// <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;
            }
        }
Beispiel #6
0
        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);
        }