Beispiel #1
0
        bool ShouldDeclareSemantics(InstructionToken instruction, RegisterType registerType)
        {
            if (registerType == RegisterType.MiscType)
            {
                return(false);
            }
            if (registerType == RegisterType.Addr)
            {
                return(false);
            }
            if (shader.Type == ShaderType.Vertex)
            {
                return(true);
            }
            if (registerType == RegisterType.Input)
            {
                switch (instruction.GetDeclUsage())
                {
                case DeclUsage.TexCoord:
                case DeclUsage.Color:
                    return(true);

                default:
                    return(false);
                }
            }
            return(true);
        }
        private TextureLoadOutputNode CreateTextureLoadOutputNode(InstructionToken instruction, int outputComponent)
        {
            const int TextureCoordsIndex = 1;
            const int SamplerIndex       = 2;

            RegisterKey samplerRegister = instruction.GetParamRegisterKey(SamplerIndex);

            if (!_samplers.TryGetValue(samplerRegister, out HlslTreeNode samplerInput))
            {
                throw new InvalidOperationException();
            }
            var samplerRegisterInput       = (RegisterInputNode)samplerInput;
            int numSamplerOutputComponents = samplerRegisterInput.SamplerTextureDimension;

            IList <HlslTreeNode> texCoords = new List <HlslTreeNode>();

            for (int component = 0; component < numSamplerOutputComponents; component++)
            {
                RegisterComponentKey textureCoordsKey = GetParamRegisterComponentKey(instruction, TextureCoordsIndex, component);
                HlslTreeNode         textureCoord     = _activeOutputs[textureCoordsKey];
                texCoords.Add(textureCoord);
            }

            return(new TextureLoadOutputNode(samplerRegisterInput, texCoords, outputComponent));
        }
        private static RegisterComponentKey GetParamRegisterComponentKey(InstructionToken instruction, int paramIndex, int component)
        {
            RegisterKey registerKey = instruction.GetParamRegisterKey(paramIndex);

            byte[] swizzle        = instruction.GetSourceSwizzleComponents(paramIndex);
            int    componentIndex = swizzle[component];

            return(new RegisterComponentKey(registerKey, componentIndex));
        }
        private HlslTreeNode CreateDotProduct2AddNode(InstructionToken instruction)
        {
            var vector1 = GetInputComponents(instruction, 1, 2);
            var vector2 = GetInputComponents(instruction, 2, 2);
            var add     = GetInputComponents(instruction, 3, 1)[0];

            var dp2 = new AddOperation(
                new MultiplyOperation(vector1[0], vector2[0]),
                new MultiplyOperation(vector1[1], vector2[1]));

            return(new AddOperation(dp2, add));
        }
        private HlslTreeNode CreateNormalizeOutputNode(InstructionToken instruction, int outputComponent)
        {
            var inputs = new List <HlslTreeNode>();

            for (int component = 0; component < 3; component++)
            {
                IList <HlslTreeNode> componentInput = GetInputs(instruction, component);
                inputs.AddRange(componentInput);
            }

            return(new NormalizeOutputNode(inputs, outputComponent));
        }
Beispiel #6
0
        string GetSourceName(InstructionToken instruction, int srcIndex)
        {
            string sourceRegisterName = instruction.GetParamRegisterName(srcIndex);

            sourceRegisterName  = ApplyModifier(instruction.GetSourceModifier(srcIndex), sourceRegisterName);
            sourceRegisterName += instruction.GetSourceSwizzleName(srcIndex);
            if (instruction.IsRelativeAddressMode(srcIndex))
            {
                sourceRegisterName += $"[{GetSourceName(instruction, srcIndex + 1)}]";
            }
            return(sourceRegisterName);
        }
        public string GetDestinationName(InstructionToken instruction)
        {
            int         destIndex   = instruction.GetDestinationParamIndex();
            RegisterKey registerKey = instruction.GetParamRegisterKey(destIndex);

            string registerName = GetRegisterName(registerKey);

            registerName = registerName ?? instruction.GetParamRegisterName(destIndex);
            var    registerLength = GetRegisterFullLength(registerKey);
            string writeMaskName  = instruction.GetDestinationWriteMaskName(registerLength, true);

            return(string.Format("{0}{1}", registerName, writeMaskName));
        }
        private HlslTreeNode CreateDotProductNode(InstructionToken instruction)
        {
            var addends       = new List <HlslTreeNode>();
            int numComponents = instruction.Opcode == Opcode.Dp3 ? 3 : 4;

            for (int component = 0; component < numComponents; component++)
            {
                IList <HlslTreeNode> componentInput = GetInputs(instruction, component);
                var multiply = new MultiplyOperation(componentInput[0], componentInput[1]);
                addends.Add(multiply);
            }

            return(addends.Aggregate((addition, addend) => new AddOperation(addition, addend)));
        }
        private HlslTreeNode[] GetInputComponents(InstructionToken instruction, int inputParameterIndex, int numComponents)
        {
            var components = new HlslTreeNode[numComponents];

            for (int i = 0; i < numComponents; i++)
            {
                RegisterComponentKey inputKey = GetParamRegisterComponentKey(instruction, inputParameterIndex, i);
                HlslTreeNode         input    = _activeOutputs[inputKey];
                var modifier = instruction.GetSourceModifier(inputParameterIndex);
                input         = ApplyModifier(input, modifier);
                components[i] = input;
            }
            return(components);
        }
Beispiel #10
0
        string GetDestinationName(InstructionToken instruction)
        {
            var resultModifier = instruction.GetDestinationResultModifier();

            int destIndex = instruction.GetDestinationParamIndex();

            string    registerName    = instruction.GetParamRegisterName(destIndex);
            const int registerLength  = 4;
            string    writeMaskName   = instruction.GetDestinationWriteMaskName(registerLength, false);
            string    destinationName = $"{registerName}{writeMaskName}";

            if (resultModifier != ResultModifier.None)
            {
                //destinationName += "TODO:Modifier!!!";
            }
            return(destinationName);
        }
Beispiel #11
0
        string GetSourceName(InstructionToken instruction, int srcIndex, bool isLogicalIndex = true)
        {
            int dataIndex;

            if (isLogicalIndex)
            {
                // compute the actual data index, which might be different from logical index
                // because of relative addressing mode.

                // TODO: Handle relative addressing mode in a better way,
                // by using `InstructionToken.Operands`:
                // https://github.com/spacehamster/DXDecompiler/pull/6#issuecomment-782958769

                // if instruction has destination, then source starts at the index 1
                // here we assume destination won't have relative addressing,
                // so we assume destination will only occupy 1 slot,
                // that is, the start index for sources will be 1 if instruction.HasDestination is true.
                var begin = instruction.HasDestination ? 1 : 0;
                dataIndex = begin;
                while (srcIndex > begin)
                {
                    if (instruction.IsRelativeAddressMode(dataIndex))
                    {
                        ++dataIndex;
                    }
                    ++dataIndex;
                    --srcIndex;
                }
            }
            else
            {
                dataIndex = srcIndex;
            }
            string sourceRegisterName = instruction.GetParamRegisterName(dataIndex);

            sourceRegisterName = ApplyModifier(instruction.GetSourceModifier(dataIndex), sourceRegisterName);
            if (instruction.IsRelativeAddressMode(dataIndex))
            {
                sourceRegisterName += $"[{GetSourceName(instruction, dataIndex + 1, isLogicalIndex: false)}]";
            }
            sourceRegisterName += instruction.GetSourceSwizzleName(dataIndex);
            return(sourceRegisterName);
        }
        private void ParseInstruction(InstructionToken instruction)
        {
            if (instruction.HasDestination)
            {
                var newOutputs = new Dictionary <RegisterComponentKey, HlslTreeNode>();

                RegisterComponentKey[] destinationKeys = GetDestinationKeys(instruction).ToArray();
                foreach (RegisterComponentKey destinationKey in destinationKeys)
                {
                    HlslTreeNode instructionTree = CreateInstructionTree(instruction, destinationKey);
                    newOutputs[destinationKey] = instructionTree;
                }

                foreach (var output in newOutputs)
                {
                    _activeOutputs[output.Key] = output.Value;
                }
            }
        }
Beispiel #13
0
        private string GetInstructionModifier(InstructionToken instruction)
        {
            string result  = "";
            var    modifer = instruction.GetDestinationResultModifier();

            if (modifer.HasFlag(ResultModifier.Saturate))
            {
                result += "_sat";
            }
            if (modifer.HasFlag(ResultModifier.PartialPrecision))
            {
                result += "_pp";
            }
            if (modifer.HasFlag(ResultModifier.Centroid))
            {
                result += "_centroid";
            }
            return(result);
        }
        private static IEnumerable <RegisterComponentKey> GetDestinationKeys(InstructionToken instruction)
        {
            int         index       = instruction.GetDestinationParamIndex();
            RegisterKey registerKey = instruction.GetParamRegisterKey(index);

            if (registerKey.Type == RegisterType.Sampler)
            {
                yield break;
            }

            ComponentFlags mask = instruction.GetDestinationWriteMask();

            for (int component = 0; component < 4; component++)
            {
                if ((mask & (ComponentFlags)(1 << component)) == 0)
                {
                    continue;
                }

                yield return(new RegisterComponentKey(registerKey, component));
            }
        }
Beispiel #15
0
        private void WriteInstruction(InstructionToken instruction)
        {
            if (RemoveIndentInstruction(instruction))
            {
                Indent--;
            }
            if (instruction.Opcode != Opcode.Comment && instruction.Opcode != Opcode.End)
            {
                WriteIndent();
            }
            if (AddIndentInstruction(instruction))
            {
                Indent++;
            }
            switch (instruction.Opcode)
            {
            case Opcode.Abs:
                WriteLine("abs{0} {1}, {2}",
                          GetInstructionModifier(instruction),
                          GetDestinationName(instruction), GetSourceName(instruction, 1));
                break;

            case Opcode.Add:
                WriteLine("add{0} {1}, {2}, {3}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.Cmp:
                WriteLine("cmp{0} {1}, {2}, {3}, {4}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3));
                break;

            case Opcode.Dcl:
                string dclInstruction = "dcl";
                var    registerType   = instruction.GetParamRegisterType(1);
                if (ShouldDeclareSemantics(instruction, registerType))
                {
                    dclInstruction += "_" + instruction.GetDeclSemantic().ToLower();
                }
                WriteLine("{0}{1} {2}", dclInstruction, GetInstructionModifier(instruction), GetDestinationName(instruction));
                break;

            case Opcode.Def:
            {
                string modifier          = GetInstructionModifier(instruction);
                string constRegisterName = instruction.GetParamRegisterName(0);
                string constValue0       = SingleToString(instruction.GetParamBytes(1));
                string constValue1       = SingleToString(instruction.GetParamBytes(2));
                string constValue2       = SingleToString(instruction.GetParamBytes(3));
                string constValue3       = SingleToString(instruction.GetParamBytes(4));
                WriteLine("def{0} {1}, {2}, {3}, {4}, {5}", modifier, constRegisterName, constValue0, constValue1, constValue2, constValue3);
            }
            break;

            case Opcode.DefI:
            {
                string constRegisterName = instruction.GetParamRegisterName(0);
                WriteLine("defi{0} {1}, {2}, {3}, {4}, {5}",
                          GetInstructionModifier(instruction), constRegisterName,
                          instruction.Data[1], instruction.Data[2], instruction.Data[3], instruction.Data[4]);
            }
            break;

            case Opcode.DP2Add:
                WriteLine("dp2add{0} {1}, {2}, {3}, {4}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3));
                break;

            case Opcode.Dp3:
                WriteLine("dp3{0} {1}, {2}, {3}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.Dp4:
                WriteLine("dp4{0} {1}, {2}, {3}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.Else:
                WriteLine("else");
                break;

            case Opcode.Endif:
                WriteLine("endif");
                break;

            case Opcode.Exp:
                WriteLine("exp{0} {1}, {2}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1));
                break;

            case Opcode.Frc:
                WriteLine("frc{0} {1}, {2}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1));
                break;

            case Opcode.If:
                WriteLine("if {0}", GetSourceName(instruction, 0));
                break;

            case Opcode.IfC:
                WriteLine("if_{0} {1}, {2}",
                          ((IfComparison)instruction.Modifier).ToString().ToLower(),
                          GetSourceName(instruction, 0), GetSourceName(instruction, 1));
                break;

            case Opcode.Log:
                WriteLine("log{0} {1}, {2}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1));
                break;

            case Opcode.Lrp:
                WriteLine("lrp{0} {1}, {2}, {3}, {4}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3));
                break;

            case Opcode.Mad:
                WriteLine("mad{0} {1}, {2}, {3}, {4}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3));
                break;

            case Opcode.Max:
                WriteLine("max{0} {1}, {2}, {3}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.Min:
                WriteLine("min{0} {1}, {2}, {3}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.Mov:
                WriteLine("mov{0} {1}, {2}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1));
                break;

            case Opcode.MovA:
                WriteLine("mova{0} {1}, {2}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1));
                break;

            case Opcode.Mul:
                WriteLine("mul{0} {1}, {2}, {3}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.Nop:
                WriteLine("nop");
                break;

            case Opcode.Nrm:
                WriteLine("nrm{0} {1}, {2}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1));
                break;

            case Opcode.Pow:
                WriteLine("pow{0} {1}, {2}, {3}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.Rcp:
                WriteLine("rcp{0} {1}, {2}",
                          GetInstructionModifier(instruction),
                          GetDestinationName(instruction), GetSourceName(instruction, 1));
                break;

            case Opcode.Rsq:
                WriteLine("rsq{0} {1}, {2}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1));
                break;

            case Opcode.Sge:
                WriteLine("sge{0} {1}, {2}, {3}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.Slt:
                WriteLine("slt{0} {1}, {2}, {3}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.SinCos:
                if (shader.MajorVersion >= 3)
                {
                    WriteLine("sincos {0}, {1}", GetDestinationName(instruction),
                              GetSourceName(instruction, 1));
                }
                else
                {
                    WriteLine("sincos {0}, {1}, {2}, {3}", GetDestinationName(instruction),
                              GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3));
                }
                break;

            case Opcode.Sub:
                WriteLine("sub{0} {1}, {2}, {3}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.Tex:
                if ((shader.MajorVersion == 1 && shader.MinorVersion >= 4) || (shader.MajorVersion > 1))
                {
                    WriteLine("texld {0}, {1}, {2}", GetDestinationName(instruction),
                              GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                }
                else
                {
                    WriteLine("tex {0}", GetDestinationName(instruction));
                }
                break;

            case Opcode.TexLDL:
                WriteLine("texldl {0}, {1}, {2}", GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.TexKill:
                WriteLine("texkill {0}", GetDestinationName(instruction));
                break;

            case Opcode.Rep:
                WriteLine("rep {0}",
                          GetDestinationName(instruction));
                break;

            case Opcode.EndRep:
                WriteLine("endrep");
                break;

            case Opcode.DSX:
                WriteLine("dsx{0} {1}, {2}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1));
                break;

            case Opcode.DSY:
                WriteLine("dsy{0} {1}, {2}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1));
                break;

            case Opcode.TexLDD:
                WriteLine("texldd {0}, {1}, {2}, {3}, {4}", GetDestinationName(instruction), GetSourceName(instruction, 1),
                          GetSourceName(instruction, 2), GetSourceName(instruction, 3),
                          GetSourceName(instruction, 4));
                break;

            case Opcode.BreakC:
                WriteLine("break_{0} {1}, {2}",
                          ((IfComparison)instruction.Modifier).ToString().ToLower(),
                          GetSourceName(instruction, 0),
                          GetSourceName(instruction, 1));
                break;

            //TODO: Add tests for Loop, and Lit
            case Opcode.Loop:
                WriteLine("loop {0}, {1}",
                          GetSourceName(instruction, 0),
                          GetSourceName(instruction, 1));
                break;

            case Opcode.EndLoop:
                WriteLine("endloop");
                break;

            case Opcode.Lit:
                WriteLine("lit{0} {1}, {2}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1));
                break;

            case Opcode.ExpP:
                WriteLine("expp{0} {1}, {2}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1));
                break;

            case Opcode.LogP:
                WriteLine("logp{0} {1}, {2}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1));
                break;

            case Opcode.M4x4:
                WriteLine("m4x4{0} {1}, {2}, {3}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.M4x3:
                WriteLine("m4x3{0} {1}, {2}, {3}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.M3x3:
                WriteLine("m3x3{0} {1}, {2}, {3}",
                          GetInstructionModifier(instruction), GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.Call:
                WriteLine("call {0}",
                          GetSourceName(instruction, 0));
                break;

            case Opcode.Ret:
                WriteLine("ret");
                break;

            case Opcode.Label:
                WriteLine("label", GetSourceName(instruction, 0));
                break;

            case Opcode.Comment:
            case Opcode.End:
                break;

            default:
                WriteLine(instruction.Opcode.ToString());
                //WriteLine("// Warning - Not Implemented");
                throw new NotImplementedException($"Instruction not implemented {instruction.Opcode}");
            }
        }
Beispiel #16
0
        private Token ReadInstruction(ShaderModel shaderModel)
        {
            uint   instructionToken = ReadUInt32();
            Opcode opcode           = (Opcode)(instructionToken & 0xffff);

            Debug.Assert(opcode <= Opcode.Breakp || (opcode >= Opcode.Phase && opcode <= Opcode.End), $"Invalid opcode {opcode}");
            int size;

            if (opcode == Opcode.Comment)
            {
                size = (int)((instructionToken >> 16) & 0x7FFF);
            }
            else
            {
                size = (int)((instructionToken >> 24) & 0x0f);
            }
            Token token = null;

            if (opcode == Opcode.Comment)
            {
                token = new CommentToken(opcode, size, shaderModel);
                for (int i = 0; i < size; i++)
                {
                    token.Data[i] = ReadUInt32();
                }
            }
            else
            {
                token = new InstructionToken(opcode, size, shaderModel);
                var inst = token as InstructionToken;
                for (int i = 0; i < size; i++)
                {
                    token.Data[i] = ReadUInt32();
                    if (opcode == Opcode.Def || opcode == Opcode.DefB || opcode == Opcode.DefI)
                    {
                    }
                    else if (opcode == Opcode.Dcl)
                    {
                        if (i == 0)
                        {
                            inst.Operands.Add(new DeclarationOperand(token.Data[i]));
                        }
                        else
                        {
                            inst.Operands.Add(new DestinationOperand(token.Data[i]));
                        }
                    }
                    else if (i == 0 && opcode != Opcode.BreakC && opcode != Opcode.IfC && opcode != Opcode.If)
                    {
                        inst.Operands.Add(new DestinationOperand(token.Data[i]));
                    }
                    else if ((token.Data[i] & (1 << 13)) != 0)
                    {
                        //Relative Address mode
                        token.Data[i + 1] = ReadUInt32();
                        inst.Operands.Add(new SourceOperand(token.Data[i], token.Data[i + 1]));
                        i++;
                    }
                    else
                    {
                        inst.Operands.Add(new SourceOperand(token.Data[i]));
                    }
                }
            }

            if (opcode != Opcode.Comment)
            {
                token.Modifier   = (int)((instructionToken >> 16) & 0xff);
                token.Predicated = (instructionToken & 0x10000000) != 0;
                token.CoIssue    = (instructionToken & 0x40000000) != 0;
                Debug.Assert((instructionToken & 0xA0000000) == 0, $"Instruction has unexpected bits set {instructionToken & 0xE0000000}");
            }

            return(token);
        }
Beispiel #17
0
        public static void Verify(InstructionToken instruction)
        {
            //Assert(currentInstruction.Modifier == 0);

            //TODO: Why?
            Debug.Assert(!instruction.Predicated, "Instruction must not be predicated");

            switch (instruction.Opcode)
            {
            case Opcode.Dcl:
                // https://msdn.microsoft.com/en-us/library/windows/hardware/ff549176(v=vs.85).aspx
                Debug.Assert(instruction.Data.Length == 2, "Dcl expected instruction length to be 2");
                uint param0 = instruction.Data[0];
                switch (instruction.GetParamRegisterType(1))
                {
                case RegisterType.Sampler:
                    Debug.Assert((param0 & 0x07FFFFFF) == 0, "Sampler param unexpected bits set");
                    break;

                case RegisterType.Input:
                case RegisterType.Output:
                case RegisterType.Texture:
                    Debug.Assert((param0 & 0x0000FFF0) == 0, "Register param unexpected bits set");
                    Debug.Assert((param0 & 0x7FF00000) == 0, "Register param unexpected bits set");
                    break;
                }
                Debug.Assert((param0 & 0x80000000) != 0, "Register param unexpected bits set");
                break;

            case Opcode.Def:
            {
                Debug.Assert(instruction.Data.Length == 5, "Def expected instruction length to be 5");
                var registerType = instruction.GetParamRegisterType(0);
                Debug.Assert(
                    registerType == RegisterType.Const ||
                    registerType == RegisterType.Const2 ||
                    registerType == RegisterType.Const3 ||
                    registerType == RegisterType.Const4,
                    "Def unexpected register type found");
            }
            break;

            case Opcode.DefI:
            {
                Debug.Assert(instruction.Data.Length == 5, "DefI expected instruction length to be 5");
                var registerType = instruction.GetParamRegisterType(0);
                Debug.Assert(registerType == RegisterType.ConstInt, "Def unexpected register type found");
            }
            break;

            case Opcode.IfC:
                IfComparison comp = (IfComparison)instruction.Modifier;
                Debug.Assert(
                    comp == IfComparison.GT ||
                    comp == IfComparison.EQ ||
                    comp == IfComparison.GE ||
                    comp == IfComparison.LT ||
                    comp == IfComparison.NE ||
                    comp == IfComparison.LE,
                    "IfC unknown comparison type found");
                break;

            default:
                //throw new NotImplementedException();
                break;
            }
        }
        public string GetSourceName(InstructionToken instruction, int srcIndex)
        {
            string      sourceRegisterName;
            RegisterKey registerKey  = instruction.GetParamRegisterKey(srcIndex);
            var         registerType = instruction.GetParamRegisterType(srcIndex);

            switch (registerType)
            {
            case RegisterType.Const:
            case RegisterType.Const2:
            case RegisterType.Const3:
            case RegisterType.Const4:
            case RegisterType.ConstBool:
            case RegisterType.ConstInt:
                sourceRegisterName = GetSourceConstantName(instruction, srcIndex);
                if (sourceRegisterName != null)
                {
                    return(sourceRegisterName);
                }

                ParameterType parameterType;
                switch (registerType)
                {
                case RegisterType.Const:
                case RegisterType.Const2:
                case RegisterType.Const3:
                case RegisterType.Const4:
                    parameterType = ParameterType.Float;
                    break;

                case RegisterType.ConstBool:
                    parameterType = ParameterType.Bool;
                    break;

                case RegisterType.ConstInt:
                    parameterType = ParameterType.Int;
                    break;

                default:
                    throw new NotImplementedException();
                }
                var registerNumber       = instruction.GetParamRegisterNumber(srcIndex);
                ConstantDeclaration decl = FindConstant(registerNumber);
                if (decl == null)
                {
                    // Constant register not found in def statements nor the constant table
                    //TODO:
                    return($"Error {registerType}{registerNumber}");
                    //throw new NotImplementedException();
                }
                var totalOffset      = registerNumber - decl.RegisterIndex;
                var data             = decl.GetRegisterTypeByOffset(totalOffset);
                var offsetFromMember = registerNumber - data.RegisterIndex;
                sourceRegisterName = decl.GetMemberNameByOffset(totalOffset);
                if (data.Type.ParameterClass == ParameterClass.MatrixRows)
                {
                    sourceRegisterName = string.Format("{0}[{1}]", decl.Name, offsetFromMember);
                }
                else if (data.Type.ParameterClass == ParameterClass.MatrixColumns)
                {
                    sourceRegisterName = string.Format("transpose({0})[{1}]", decl.Name, offsetFromMember);
                }
                break;

            default:
                sourceRegisterName = GetRegisterName(registerKey);
                break;
            }

            sourceRegisterName = sourceRegisterName ?? instruction.GetParamRegisterName(srcIndex);

            sourceRegisterName += instruction.GetSourceSwizzleName(srcIndex, true);
            return(ApplyModifier(instruction.GetSourceModifier(srcIndex), sourceRegisterName));
        }
        private string GetSourceConstantName(InstructionToken instruction, int srcIndex)
        {
            var registerType   = instruction.GetParamRegisterType(srcIndex);
            var registerNumber = instruction.GetParamRegisterNumber(srcIndex);

            switch (registerType)
            {
            case RegisterType.ConstBool:
                //throw new NotImplementedException();
                return(null);

            case RegisterType.ConstInt:
            {
                var constantInt = _constantIntDefinitions.FirstOrDefault(x => x.RegisterIndex == registerNumber);
                if (constantInt == null)
                {
                    return(null);
                }
                byte[] swizzle  = instruction.GetSourceSwizzleComponents(srcIndex);
                uint[] constant =
                {
                    constantInt[swizzle[0]],
                    constantInt[swizzle[1]],
                    constantInt[swizzle[2]],
                    constantInt[swizzle[3]]
                };

                switch (instruction.GetSourceModifier(srcIndex))
                {
                case SourceModifier.None:
                    break;

                case SourceModifier.Negate:
                    throw new NotImplementedException();

                /*
                 * for (int i = 0; i < 4; i++)
                 * {
                 *      constant[i] = -constant[i];
                 * }
                 * break;*/
                default:
                    throw new NotImplementedException();
                }

                int destLength = instruction.GetDestinationMaskLength();
                switch (destLength)
                {
                case 1:
                    return(constant[0].ToString());

                case 2:
                    if (constant[0] == constant[1])
                    {
                        return(constant[0].ToString());
                    }
                    return($"int2({constant[0]}, {constant[1]})");

                case 3:
                    if (constant[0] == constant[1] && constant[0] == constant[2])
                    {
                        return(constant[0].ToString());
                    }
                    return($"int3({constant[0]}, {constant[1]}, {constant[2]})");

                case 4:
                    if (constant[0] == constant[1] && constant[0] == constant[2] && constant[0] == constant[3])
                    {
                        return(constant[0].ToString());
                    }
                    return($"int4({constant[0]}, {constant[1]}, {constant[2]}, {constant[3]})");

                default:
                    throw new InvalidOperationException();
                }
            }

            case RegisterType.Const:
            case RegisterType.Const2:
            case RegisterType.Const3:
            case RegisterType.Const4:
            {
                var constantRegister = _constantDefinitions.FirstOrDefault(x => x.RegisterIndex == registerNumber);
                if (constantRegister == null)
                {
                    return(null);
                }

                byte[]  swizzle  = instruction.GetSourceSwizzleComponents(srcIndex);
                float[] constant =
                {
                    constantRegister[swizzle[0]],
                    constantRegister[swizzle[1]],
                    constantRegister[swizzle[2]],
                    constantRegister[swizzle[3]]
                };

                switch (instruction.GetSourceModifier(srcIndex))
                {
                case SourceModifier.None:
                    break;

                case SourceModifier.Negate:
                    for (int i = 0; i < 4; i++)
                    {
                        constant[i] = -constant[i];
                    }
                    break;

                default:
                    throw new NotImplementedException();
                }

                int destLength;
                if (instruction.HasDestination)
                {
                    destLength = instruction.GetDestinationMaskLength();
                }
                else
                {
                    if (instruction.Opcode == Opcode.If || instruction.Opcode == Opcode.IfC)
                    {
                        // TODO
                    }
                    destLength = 4;
                }
                switch (destLength)
                {
                case 1:
                    return(constant[0].ToString(_culture));

                case 2:
                    if (constant[0] == constant[1])
                    {
                        return(constant[0].ToString(_culture));
                    }
                    return(string.Format("float2({0}, {1})",
                                         constant[0].ToString(_culture),
                                         constant[1].ToString(_culture)));

                case 3:
                    if (constant[0] == constant[1] && constant[0] == constant[2])
                    {
                        return(constant[0].ToString(_culture));
                    }
                    return(string.Format("float3({0}, {1}, {2})",
                                         constant[0].ToString(_culture),
                                         constant[1].ToString(_culture),
                                         constant[2].ToString(_culture)));

                case 4:
                    if (constant[0] == constant[1] && constant[0] == constant[2] && constant[0] == constant[3])
                    {
                        return(constant[0].ToString(_culture));
                    }
                    return(string.Format("float4({0}, {1}, {2}, {3})",
                                         constant[0].ToString(_culture),
                                         constant[1].ToString(_culture),
                                         constant[2].ToString(_culture),
                                         constant[3].ToString(_culture)));

                default:
                    throw new InvalidOperationException();
                }
            }

            default:
                return(null);
            }
        }
Beispiel #20
0
 private string GetDestinationName(InstructionToken instruction)
 {
     return(_registers.GetDestinationName(instruction));
 }
Beispiel #21
0
 private string GetSourceName(InstructionToken instruction, int srcIndex)
 {
     return(_registers.GetSourceName(instruction, srcIndex));
 }
Beispiel #22
0
        private void WriteInstruction(InstructionToken instruction)
        {
            WriteIndent();
            WriteLine($"// {instruction}");
            switch (instruction.Opcode)
            {
            case Opcode.Def:
            case Opcode.DefI:
            case Opcode.Dcl:
            case Opcode.End:
                return;

            // these opcodes doesn't need indents:
            case Opcode.Else:
                Indent--;
                WriteIndent();
                WriteLine("} else {");
                Indent++;
                return;

            case Opcode.Endif:
                Indent--;
                WriteIndent();
                WriteLine("}");
                return;

            case Opcode.EndRep:
                Indent--;
                _iterationDepth--;
                WriteIndent();
                WriteLine("}");
                return;
            }
            WriteIndent();
            switch (instruction.Opcode)
            {
            case Opcode.Abs:
                WriteLine("{0} = abs({1});", GetDestinationName(instruction),
                          GetSourceName(instruction, 1));
                break;

            case Opcode.Add:
                WriteLine("{0} = {1} + {2};", GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.Cmp:
                // TODO: should be per-component
                WriteLine("{0} = ({1} >= 0) ? {2} : {3};", GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3));
                break;

            case Opcode.DP2Add:
                WriteLine("{0} = dot({1}, {2}) + {3};", GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3));
                break;

            case Opcode.Dp3:
                WriteLine("{0} = dot({1}, {2});", GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.Dp4:
                WriteLine("{0} = dot({1}, {2});", GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.Exp:
                WriteLine("{0} = exp2({1});", GetDestinationName(instruction), GetSourceName(instruction, 1));
                break;

            case Opcode.Frc:
                WriteLine("{0} = frac({1});", GetDestinationName(instruction), GetSourceName(instruction, 1));
                break;

            case Opcode.If:
                WriteLine("if ({0}) {{", GetSourceName(instruction, 0));
                Indent++;
                break;

            case Opcode.IfC:
                if ((IfComparison)instruction.Modifier == IfComparison.GE &&
                    instruction.GetSourceModifier(0) == SourceModifier.AbsAndNegate &&
                    instruction.GetSourceModifier(1) == SourceModifier.Abs &&
                    instruction.GetParamRegisterName(0) + instruction.GetSourceSwizzleName(0) ==
                    instruction.GetParamRegisterName(1) + instruction.GetSourceSwizzleName(1))
                {
                    WriteLine("if ({0} == 0) {{", instruction.GetParamRegisterName(0) + instruction.GetSourceSwizzleName(0));
                }
                else if ((IfComparison)instruction.Modifier == IfComparison.LT &&
                         instruction.GetSourceModifier(0) == SourceModifier.AbsAndNegate &&
                         instruction.GetSourceModifier(1) == SourceModifier.Abs &&
                         instruction.GetParamRegisterName(0) + instruction.GetSourceSwizzleName(0) ==
                         instruction.GetParamRegisterName(1) + instruction.GetSourceSwizzleName(1))
                {
                    WriteLine("if ({0} != 0) {{", instruction.GetParamRegisterName(0) + instruction.GetSourceSwizzleName(0));
                }
                else
                {
                    string ifComparison;
                    switch ((IfComparison)instruction.Modifier)
                    {
                    case IfComparison.GT:
                        ifComparison = ">";
                        break;

                    case IfComparison.EQ:
                        ifComparison = "==";
                        break;

                    case IfComparison.GE:
                        ifComparison = ">=";
                        break;

                    case IfComparison.LE:
                        ifComparison = "<=";
                        break;

                    case IfComparison.NE:
                        ifComparison = "!=";
                        break;

                    case IfComparison.LT:
                        ifComparison = "<";
                        break;

                    default:
                        throw new InvalidOperationException();
                    }
                    WriteLine("if ({0} {2} {1}) {{", GetSourceName(instruction, 0), GetSourceName(instruction, 1), ifComparison);
                }
                Indent++;
                break;

            case Opcode.Log:
                WriteLine("{0} = log2({1});", GetDestinationName(instruction), GetSourceName(instruction, 1));
                break;

            case Opcode.Lrp:
                WriteLine("{0} = lerp({2}, {3}, {1});", GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3));
                break;

            case Opcode.Mad:
                WriteLine("{0} = {1} * {2} + {3};", GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3));
                break;

            case Opcode.Max:
                WriteLine("{0} = max({1}, {2});", GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.Min:
                WriteLine("{0} = min({1}, {2});", GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.Mov:
                WriteLine("{0} = {1};", GetDestinationName(instruction), GetSourceName(instruction, 1));
                break;

            case Opcode.MovA:
                WriteLine("{0} = {1};", GetDestinationName(instruction), GetSourceName(instruction, 1));
                break;

            case Opcode.Mul:
                WriteLine("{0} = {1} * {2};", GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.Nrm:
                WriteLine("{0} = normalize({1});", GetDestinationName(instruction), GetSourceName(instruction, 1));
                break;

            case Opcode.Pow:
                WriteLine("{0} = pow({1}, {2});", GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.Rcp:
                WriteLine("{0} = 1 / {1};", GetDestinationName(instruction), GetSourceName(instruction, 1));
                break;

            case Opcode.Rsq:
                WriteLine("{0} = 1 / sqrt({1});", GetDestinationName(instruction), GetSourceName(instruction, 1));
                break;

            case Opcode.Sge:
                if (instruction.GetSourceModifier(1) == SourceModifier.AbsAndNegate &&
                    instruction.GetSourceModifier(2) == SourceModifier.Abs &&
                    instruction.GetParamRegisterName(1) + instruction.GetSourceSwizzleName(1) ==
                    instruction.GetParamRegisterName(2) + instruction.GetSourceSwizzleName(2))
                {
                    WriteLine("{0} = ({1} == 0) ? 1 : 0;", GetDestinationName(instruction),
                              instruction.GetParamRegisterName(1) + instruction.GetSourceSwizzleName(1));
                }
                else
                {
                    WriteLine("{0} = ({1} >= {2}) ? 1 : 0;", GetDestinationName(instruction), GetSourceName(instruction, 1),
                              GetSourceName(instruction, 2));
                }
                break;

            case Opcode.Slt:
                WriteLine("{0} = ({1} < {2}) ? 1 : 0;", GetDestinationName(instruction), GetSourceName(instruction, 1),
                          GetSourceName(instruction, 2));
                break;

            case Opcode.SinCos:
                WriteLine("sincos({1}, {0}, {0});", GetDestinationName(instruction), GetSourceName(instruction, 1));
                break;

            case Opcode.Sub:
                WriteLine("{0} = {1} - {2};", GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.Tex:
                if ((_shader.MajorVersion == 1 && _shader.MinorVersion >= 4) || (_shader.MajorVersion > 1))
                {
                    WriteLine("{0} = tex2D({2}, {1});", GetDestinationName(instruction),
                              GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                }
                else
                {
                    WriteLine("{0} = tex2D();", GetDestinationName(instruction));
                }
                break;

            case Opcode.TexLDL:
                WriteLine("{0} = tex2Dlod({2}, {1});", GetDestinationName(instruction),
                          GetSourceName(instruction, 1), GetSourceName(instruction, 2));
                break;

            case Opcode.Comment:
            {
                byte[] bytes = new byte[instruction.Data.Length * sizeof(uint)];
                Buffer.BlockCopy(instruction.Data, 0, bytes, 0, bytes.Length);
                var ascii = FormatUtil.BytesToAscii(bytes);
                WriteLine($"// Comment: {ascii}");
                break;
            }

            case Opcode.Rep:
                WriteLine("for (int it{0} = 0; it{0} < {1}; ++it{0}) {{", _iterationDepth, GetSourceName(instruction, 0));
                _iterationDepth++;
                Indent++;
                break;

            case Opcode.TexKill:
                WriteLine("clip({0});", GetDestinationName(instruction));
                break;

            default:
                throw new NotImplementedException(instruction.Opcode.ToString());
            }
        }
 public RegisterDeclaration(InstructionToken declInstruction)
 {
     RegisterKey   = declInstruction.GetParamRegisterKey(1);
     _semantic     = declInstruction.GetDeclSemantic();
     _maskedLength = declInstruction.GetDestinationMaskedLength();
 }
        private HlslTreeNode CreateInstructionTree(InstructionToken instruction, RegisterComponentKey destinationKey)
        {
            int componentIndex = destinationKey.ComponentIndex;

            switch (instruction.Opcode)
            {
            case Opcode.Dcl:
            {
                var shaderInput = new RegisterInputNode(destinationKey);
                return(shaderInput);
            }

            case Opcode.Def:
            {
                var constant = new ConstantNode(instruction.GetParamSingle(componentIndex + 1));
                return(constant);
            }

            case Opcode.DefI:
            {
                var constant = new ConstantNode(instruction.GetParamInt(componentIndex + 1));
                return(constant);
            }

            case Opcode.DefB:
            {
                throw new NotImplementedException();
            }

            case Opcode.Abs:
            case Opcode.Add:
            case Opcode.Cmp:
            case Opcode.Frc:
            case Opcode.Lrp:
            case Opcode.Mad:
            case Opcode.Max:
            case Opcode.Min:
            case Opcode.Mov:
            case Opcode.Mul:
            case Opcode.Pow:
            case Opcode.Rcp:
            case Opcode.Rsq:
            case Opcode.SinCos:
            case Opcode.Sge:
            case Opcode.Slt:
            {
                HlslTreeNode[] inputs = GetInputs(instruction, componentIndex);
                switch (instruction.Opcode)
                {
                case Opcode.Abs:
                    return(new AbsoluteOperation(inputs[0]));

                case Opcode.Cmp:
                    return(new CompareOperation(inputs[0], inputs[1], inputs[2]));

                case Opcode.Frc:
                    return(new FractionalOperation(inputs[0]));

                case Opcode.Lrp:
                    return(new LinearInterpolateOperation(inputs[0], inputs[1], inputs[2]));

                case Opcode.Max:
                    return(new MaximumOperation(inputs[0], inputs[1]));

                case Opcode.Min:
                    return(new MinimumOperation(inputs[0], inputs[1]));

                case Opcode.Mov:
                    return(new MoveOperation(inputs[0]));

                case Opcode.Add:
                    return(new AddOperation(inputs[0], inputs[1]));

                case Opcode.Mul:
                    return(new MultiplyOperation(inputs[0], inputs[1]));

                case Opcode.Mad:
                    return(new MultiplyAddOperation(inputs[0], inputs[1], inputs[2]));

                case Opcode.Pow:
                    return(new PowerOperation(inputs[0], inputs[1]));

                case Opcode.Rcp:
                    return(new ReciprocalOperation(inputs[0]));

                case Opcode.Rsq:
                    return(new ReciprocalSquareRootOperation(inputs[0]));

                case Opcode.SinCos:
                    if (componentIndex == 0)
                    {
                        return(new CosineOperation(inputs[0]));
                    }
                    return(new SineOperation(inputs[0]));

                case Opcode.Sge:
                    return(new SignGreaterOrEqualOperation(inputs[0], inputs[1]));

                case Opcode.Slt:
                    return(new SignLessOperation(inputs[0], inputs[1]));

                default:
                    throw new NotImplementedException();
                }
            }

            case Opcode.Tex:
            case Opcode.TexLDL:
                return(CreateTextureLoadOutputNode(instruction, componentIndex));

            case Opcode.DP2Add:
                return(CreateDotProduct2AddNode(instruction));

            case Opcode.Dp3:
            case Opcode.Dp4:
                return(CreateDotProductNode(instruction));

            case Opcode.Nrm:
                return(CreateNormalizeOutputNode(instruction, componentIndex));

            default:
                throw new NotImplementedException($"{instruction.Opcode} not implemented");
            }
        }
Beispiel #25
0
        //Refer https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx9-graphics-reference-asm-vs-instructions-vs-3-0
        //Refer https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx9-graphics-reference-asm-ps-instructions-ps-3-0
        public static int GetInstructionSlotCount(this InstructionToken token)
        {
            switch (token.Opcode)
            {
            case Opcode.Dcl:
            case Opcode.Def:
            case Opcode.DefB:
            case Opcode.DefI:
            case Opcode.Label:
            case Opcode.Comment:
            case Opcode.End:
                return(0);

            case Opcode.Abs:
            case Opcode.Add:
            case Opcode.Break:
            case Opcode.Dp3:
            case Opcode.Dp4:
            case Opcode.Dst:
            case Opcode.Else:
            case Opcode.Endif:
            case Opcode.Exp:
            case Opcode.Frc:
            case Opcode.Log:
            case Opcode.LogP:
            case Opcode.Mad:
            case Opcode.Max:
            case Opcode.Min:
            case Opcode.Mov:
            case Opcode.MovA:
            case Opcode.Mul:
            case Opcode.Nop:
            case Opcode.Rcp:
            case Opcode.Ret:
            case Opcode.Rsq:
            case Opcode.SetP:
            case Opcode.Sge:
            case Opcode.Slt:
            case Opcode.Sub:
            case Opcode.Cmp:
                return(1);

            case Opcode.Lrp:
                return(1);

            case Opcode.Call:
            case Opcode.Crs:
            case Opcode.EndLoop:
            case Opcode.EndRep:
            case Opcode.M3x2:
            case Opcode.DP2Add:
            case Opcode.DSX:
            case Opcode.DSY:
            case Opcode.TexKill:
                return(2);

            case Opcode.CallNZ:
            case Opcode.BreakC:
            case Opcode.Breakp:
            case Opcode.If:
            case Opcode.IfC:
            case Opcode.Lit:
            case Opcode.Loop:
            case Opcode.M3x3:
            case Opcode.M4x3:
            case Opcode.Nrm:
            case Opcode.Pow:
            case Opcode.Rep:
            case Opcode.Sgn:
            case Opcode.TexLDD:
                return(3);

            case Opcode.M3x4:
            case Opcode.M4x4:
                return(4);

            //TODO: can't find opcode
            //case Opcode.TexLdb:
            //	return 6
            case Opcode.SinCos:
                return(8);

            case Opcode.TexLDL:
            {
                var textureType = token.GetDeclSamplerTextureType();
                if (textureType == SamplerTextureType.Cube)
                {
                    return(5);
                }
                else
                {
                    return(2);
                }
            }

            //TexLD
            case Opcode.Tex:
            {
                var textureType = token.GetDeclSamplerTextureType();
                if (textureType == SamplerTextureType.Cube)
                {
                    return(4);
                }
                else
                {
                    return(1);
                }
            }

            //Guessing
            case Opcode.ExpP:
                return(1);

            default:
                throw new NotImplementedException($"Instruction not implemented {token.Opcode}");
            }
        }
        Token ReadInstruction(BytecodeReader reader)
        {
            uint   instructionToken = reader.ReadUInt32();
            Opcode opcode           = (Opcode)(instructionToken & 0xffff);
            int    size;

            if (opcode == Opcode.Comment)
            {
                size = (int)((instructionToken >> 16) & 0x7FFF);
            }
            else
            {
                size = (int)((instructionToken >> 24) & 0x0f);
            }
            Token token = null;

            if (opcode == Opcode.Comment)
            {
                var fourCC = reader.ReadUInt32();
                if (KnownCommentTypes.ContainsKey(fourCC))
                {
                    var commentReader = reader.CopyAtCurrentPosition();
                    reader.ReadBytes(size * 4 - 4);
                    switch (KnownCommentTypes[fourCC])
                    {
                    case CommentType.CTAB:
                        ConstantTable = ConstantTable.Parse(commentReader);
                        return(null);

                    case CommentType.C**T:
                        Cli = CliToken.Parse(commentReader);
                        return(null);

                    case CommentType.FXLC:
                        Fxlc = FxlcBlock.Parse(commentReader);
                        return(null);

                    case CommentType.PRES:
                        Preshader = Preshader.Parse(commentReader);
                        return(null);

                    case CommentType.PRSI:
                        Prsi = PrsiToken.Parse(commentReader);
                        return(null);
                    }
                }
                token         = new CommentToken(opcode, size, this);
                token.Data[0] = fourCC;
                for (int i = 1; i < size; i++)
                {
                    token.Data[i] = reader.ReadUInt32();
                }
            }
            else
            {
                token = new InstructionToken(opcode, size, this);
                var inst = token as InstructionToken;

                for (int i = 0; i < size; i++)
                {
                    token.Data[i] = reader.ReadUInt32();
                    if (opcode == Opcode.Def || opcode == Opcode.DefB || opcode == Opcode.DefI)
                    {
                        if (i == 0)
                        {
                            inst.Operands.Add(new DestinationOperand(token.Data[i]));
                        }
                    }
                    else if (opcode == Opcode.Dcl)
                    {
                        if (i == 0)
                        {
                            inst.Operands.Add(new DeclarationOperand(token.Data[i]));
                        }
                        else
                        {
                            inst.Operands.Add(new DestinationOperand(token.Data[i]));
                        }
                    }
                    else if (i == 0 && opcode.HasDestination())
                    {
                        if ((token.Data[i] & (1 << 13)) != 0)
                        {
                            //Relative Address mode
                            token.Data[i + 1] = reader.ReadUInt32();
                            inst.Operands.Add(new DestinationOperand(token.Data[i], token.Data[i + 1]));
                            i++;
                        }
                        else
                        {
                            inst.Operands.Add(new DestinationOperand(token.Data[i]));
                        }
                    }
                    else if ((token.Data[i] & (1 << 13)) != 0)
                    {
                        //Relative Address mode
                        token.Data[i + 1] = reader.ReadUInt32();
                        inst.Operands.Add(new SourceOperand(token.Data[i], token.Data[i + 1]));
                        i++;
                    }
                    else
                    {
                        inst.Operands.Add(new SourceOperand(token.Data[i]));
                    }
                }
                if (opcode != Opcode.Comment)
                {
                    token.Modifier   = (int)((instructionToken >> 16) & 0xff);
                    token.Predicated = (instructionToken & 0x10000000) != 0;
                    token.CoIssue    = (instructionToken & 0x40000000) != 0;
                    Debug.Assert((instructionToken & 0xA0000000) == 0, $"Instruction has unexpected bits set {instructionToken & 0xE0000000}");
                }
            }
            return(token);
        }