Esempio n. 1
0
        public static void Iadd_I32(ShaderIrBlock Block, long OpCode, int Position)
        {
            ShaderIrNode OperA = OpCode.Gpr8();
            ShaderIrNode OperB = OpCode.Imm32_20();

            bool NegA = OpCode.Read(56);

            OperA = GetAluIneg(OperA, NegA);

            ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Add, OperA, OperB);

            Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
        }
Esempio n. 2
0
        public static void Ipa(ShaderIrBlock Block, long OpCode, int Position)
        {
            ShaderIrNode OperA = OpCode.Abuf28();
            ShaderIrNode OperB = OpCode.Gpr20();

            ShaderIpaMode Mode = (ShaderIpaMode)(OpCode.Read(54, 3));

            ShaderIrMetaIpa Meta = new ShaderIrMetaIpa(Mode);

            ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Ipa, OperA, OperB, null, Meta);

            Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
        }
        public static ShaderIrNode ExtendTo32(ShaderIrNode Node, bool Signed, int Size)
        {
            int Shift = 32 - Size;

            ShaderIrInst RightShift = Signed
                ? ShaderIrInst.Asr
                : ShaderIrInst.Lsr;

            Node = new ShaderIrOp(ShaderIrInst.Lsl, Node, new ShaderIrOperImm(Shift));
            Node = new ShaderIrOp(RightShift, Node, new ShaderIrOperImm(Shift));

            return(Node);
        }
Esempio n. 4
0
        private static void EmitLop(ShaderIrBlock block, long opCode, ShaderOper oper)
        {
            int subOp = opCode.Read(41, 3);

            bool invA = opCode.Read(39);
            bool invB = opCode.Read(40);

            ShaderIrInst inst = 0;

            switch (subOp)
            {
            case 0: inst = ShaderIrInst.And; break;

            case 1: inst = ShaderIrInst.Or;  break;

            case 2: inst = ShaderIrInst.Xor; break;
            }

            ShaderIrNode operA = GetAluNot(opCode.Gpr8(), invA);
            ShaderIrNode operB;

            switch (oper)
            {
            case ShaderOper.Cr:  operB = opCode.Cbuf34();   break;

            case ShaderOper.Imm: operB = opCode.Imm19_20(); break;

            case ShaderOper.Rr:  operB = opCode.Gpr20();    break;

            default: throw new ArgumentException(nameof(oper));
            }

            operB = GetAluNot(operB, invB);

            ShaderIrNode op;

            if (subOp < 3)
            {
                op = new ShaderIrOp(inst, operA, operB);
            }
            else
            {
                op = operB;
            }

            ShaderIrNode compare = new ShaderIrOp(ShaderIrInst.Cne, op, new ShaderIrOperImm(0));

            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Pred48(), compare)));

            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op)));
        }
Esempio n. 5
0
        private static void EmitLop(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
        {
            int SubOp = (int)(OpCode >> 41) & 3;

            bool InvA = ((OpCode >> 39) & 1) != 0;
            bool InvB = ((OpCode >> 40) & 1) != 0;

            ShaderIrInst Inst = 0;

            switch (SubOp)
            {
            case 0: Inst = ShaderIrInst.And; break;

            case 1: Inst = ShaderIrInst.Or;  break;

            case 2: Inst = ShaderIrInst.Xor; break;
            }

            ShaderIrNode OperA = GetAluNot(GetOperGpr8(OpCode), InvA);
            ShaderIrNode OperB;

            switch (Oper)
            {
            case ShaderOper.CR:  OperB = GetOperCbuf34(OpCode); break;

            case ShaderOper.Imm: OperB = GetOperImm19_20(OpCode); break;

            case ShaderOper.RR:  OperB = GetOperGpr20(OpCode); break;

            default: throw new ArgumentException(nameof(Oper));
            }

            OperB = GetAluNot(OperB, InvB);

            ShaderIrNode Op;

            if (SubOp < 3)
            {
                Op = new ShaderIrOp(Inst, OperA, OperB);
            }
            else
            {
                Op = OperB;
            }

            ShaderIrNode Compare = new ShaderIrOp(ShaderIrInst.Cne, Op, new ShaderIrOperImm(0));

            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperPred48(OpCode), Compare), OpCode));

            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
        }
Esempio n. 6
0
        private static void EmitLop(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
        {
            int SubOp = OpCode.Read(41, 3);

            bool InvA = OpCode.Read(39);
            bool InvB = OpCode.Read(40);

            ShaderIrInst Inst = 0;

            switch (SubOp)
            {
            case 0: Inst = ShaderIrInst.And; break;

            case 1: Inst = ShaderIrInst.Or;  break;

            case 2: Inst = ShaderIrInst.Xor; break;
            }

            ShaderIrNode OperA = GetAluNot(OpCode.Gpr8(), InvA);
            ShaderIrNode OperB;

            switch (Oper)
            {
            case ShaderOper.CR:  OperB = OpCode.Cbuf34();   break;

            case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;

            case ShaderOper.RR:  OperB = OpCode.Gpr20();    break;

            default: throw new ArgumentException(nameof(Oper));
            }

            OperB = GetAluNot(OperB, InvB);

            ShaderIrNode Op;

            if (SubOp < 3)
            {
                Op = new ShaderIrOp(Inst, OperA, OperB);
            }
            else
            {
                Op = OperB;
            }

            ShaderIrNode Compare = new ShaderIrOp(ShaderIrInst.Cne, Op, new ShaderIrOperImm(0));

            Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Pred48(), Compare)));

            Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
        }
Esempio n. 7
0
        private static void EmitTex(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst)
        {
            //TODO: Support other formats.
            ShaderIrNode OperA = GetOperGpr8(OpCode);
            ShaderIrNode OperB = GetOperGpr20(OpCode);
            ShaderIrNode OperC = GetOperImm13_36(OpCode);

            int LutIndex;

            LutIndex  = GetOperGpr0(OpCode).Index != ShaderIrOperGpr.ZRIndex ? 1 : 0;
            LutIndex |= GetOperGpr28(OpCode).Index != ShaderIrOperGpr.ZRIndex ? 2 : 0;

            int ChMask = MaskLut[LutIndex, (OpCode >> 50) & 7];

            for (int Ch = 0; Ch < 4; Ch++)
            {
                ShaderIrOperGpr Dst = new ShaderIrOperGpr(TempRegStart + Ch);

                ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch);

                ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB, OperC, Meta);

                Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Op), OpCode));
            }

            int RegInc = 0;

            for (int Ch = 0; Ch < 4; Ch++)
            {
                if (!IsChannelUsed(ChMask, Ch))
                {
                    continue;
                }

                ShaderIrOperGpr Src = new ShaderIrOperGpr(TempRegStart + Ch);

                ShaderIrOperGpr Dst = (RegInc >> 1) != 0
                    ? GetOperGpr28(OpCode)
                    : GetOperGpr0(OpCode);

                Dst.Index += RegInc++ & 1;

                if (Dst.Index >= ShaderIrOperGpr.ZRIndex)
                {
                    continue;
                }

                Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Src), OpCode));
            }
        }
Esempio n. 8
0
        public static ShaderIrNode ExtendTo32(ShaderIrNode Node, bool Signed, ShaderIrNode Size)
        {
            ShaderIrOperImm WordSize = new ShaderIrOperImm(32);

            ShaderIrOp Shift = new ShaderIrOp(ShaderIrInst.Sub, WordSize, Size);

            ShaderIrInst RightShift = Signed
                ? ShaderIrInst.Asr
                : ShaderIrInst.Lsr;

            Node = new ShaderIrOp(ShaderIrInst.Lsl, Node, Shift);
            Node = new ShaderIrOp(RightShift, Node, Shift);

            return(Node);
        }
Esempio n. 9
0
        public static void Fadd_I32(ShaderIrBlock Block, long OpCode)
        {
            ShaderIrNode OperA = GetOperGpr8(OpCode);
            ShaderIrNode OperB = GetOperImmf32_20(OpCode);

            bool NegB = ((OpCode >> 53) & 1) != 0;
            bool AbsA = ((OpCode >> 54) & 1) != 0;
            bool NegA = ((OpCode >> 56) & 1) != 0;
            bool AbsB = ((OpCode >> 57) & 1) != 0;

            OperA = GetAluFabsFneg(OperA, AbsA, NegA);
            OperB = GetAluFabsFneg(OperB, AbsB, NegB);

            ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Fadd, OperA, OperB);

            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
        }
Esempio n. 10
0
        public static void Fadd_I32(ShaderIrBlock block, long opCode, int position)
        {
            ShaderIrNode operA = opCode.Gpr8();
            ShaderIrNode operB = opCode.Immf32_20();

            bool negB = opCode.Read(53);
            bool absA = opCode.Read(54);
            bool negA = opCode.Read(56);
            bool absB = opCode.Read(57);

            operA = GetAluFabsFneg(operA, absA, negA);
            operB = GetAluFabsFneg(operB, absB, negB);

            ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Fadd, operA, operB);

            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op)));
        }
Esempio n. 11
0
        public static void Fadd_I32(ShaderIrBlock Block, long OpCode, int Position)
        {
            ShaderIrNode OperA = OpCode.Gpr8();
            ShaderIrNode OperB = OpCode.Immf32_20();

            bool NegB = OpCode.Read(53);
            bool AbsA = OpCode.Read(54);
            bool NegA = OpCode.Read(56);
            bool AbsB = OpCode.Read(57);

            OperA = GetAluFabsFneg(OperA, AbsA, NegA);
            OperB = GetAluFabsFneg(OperB, AbsB, NegB);

            ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Fadd, OperA, OperB);

            Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
        }
Esempio n. 12
0
        public static void Texq(ShaderIrBlock Block, long OpCode)
        {
            ShaderIrNode OperD = GetOperGpr0(OpCode);
            ShaderIrNode OperA = GetOperGpr8(OpCode);

            ShaderTexqInfo Info = (ShaderTexqInfo)((OpCode >> 22) & 0x1f);

            ShaderIrMetaTexq Meta0 = new ShaderIrMetaTexq(Info, 0);
            ShaderIrMetaTexq Meta1 = new ShaderIrMetaTexq(Info, 1);

            ShaderIrNode OperC = GetOperImm13_36(OpCode);

            ShaderIrOp Op0 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, OperC, Meta0);
            ShaderIrOp Op1 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, OperC, Meta1);

            Block.AddNode(GetPredNode(new ShaderIrAsg(OperD, Op0), OpCode));
            Block.AddNode(GetPredNode(new ShaderIrAsg(OperA, Op1), OpCode)); //Is this right?
        }
Esempio n. 13
0
        public static void Texq(ShaderIrBlock block, long opCode, int position)
        {
            ShaderIrNode operD = opCode.Gpr0();
            ShaderIrNode operA = opCode.Gpr8();

            ShaderTexqInfo info = (ShaderTexqInfo)(opCode.Read(22, 0x1f));

            ShaderIrMetaTexq meta0 = new ShaderIrMetaTexq(info, 0);
            ShaderIrMetaTexq meta1 = new ShaderIrMetaTexq(info, 1);

            ShaderIrNode operC = opCode.Imm13_36();

            ShaderIrOp op0 = new ShaderIrOp(ShaderIrInst.Texq, operA, null, operC, meta0);
            ShaderIrOp op1 = new ShaderIrOp(ShaderIrInst.Texq, operA, null, operC, meta1);

            block.AddNode(opCode.PredNode(new ShaderIrAsg(operD, op0)));
            block.AddNode(opCode.PredNode(new ShaderIrAsg(operA, op1))); //Is this right?
        }
Esempio n. 14
0
        public static void Texq(ShaderIrBlock Block, long OpCode, int Position)
        {
            ShaderIrNode OperD = OpCode.Gpr0();
            ShaderIrNode OperA = OpCode.Gpr8();

            ShaderTexqInfo Info = (ShaderTexqInfo)(OpCode.Read(22, 0x1f));

            ShaderIrMetaTexq Meta0 = new ShaderIrMetaTexq(Info, 0);
            ShaderIrMetaTexq Meta1 = new ShaderIrMetaTexq(Info, 1);

            ShaderIrNode OperC = OpCode.Imm13_36();

            ShaderIrOp Op0 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, OperC, Meta0);
            ShaderIrOp Op1 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, OperC, Meta1);

            Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperD, Op0)));
            Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperA, Op1))); //Is this right?
        }
Esempio n. 15
0
        public static void Texs(ShaderIrBlock Block, long OpCode)
        {
            //TODO: Support other formats.
            ShaderIrNode OperA = GetOperGpr8(OpCode);
            ShaderIrNode OperB = GetOperGpr20(OpCode);
            ShaderIrNode OperC = GetOperGpr28(OpCode);
            ShaderIrNode OperD = GetOperImm13_36(OpCode);

            for (int Ch = 0; Ch < 4; Ch++)
            {
                ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Texr + Ch, OperA, OperB, OperD);

                ShaderIrOperGpr Dst = GetOperGpr0(OpCode);

                Dst.Index += Ch;

                Block.AddNode(new ShaderIrAsg(Dst, Op));
            }
        }
Esempio n. 16
0
        private static void EmitTex(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst)
        {
            //TODO: Support other formats.
            ShaderIrNode OperA = GetOperGpr8(OpCode);
            ShaderIrNode OperB = GetOperGpr20(OpCode);
            ShaderIrNode OperC = GetOperImm13_36(OpCode);

            for (int Ch = 0; Ch < 4; Ch++)
            {
                //Assign it to a temp because the destination registers
                //may be used as texture coord input aswell.
                ShaderIrOperGpr Dst = new ShaderIrOperGpr(0x100 + Ch);

                ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch);

                ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB, OperC, Meta);

                Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Op), OpCode));
            }

            for (int Ch = 0; Ch < 4; Ch++)
            {
                ShaderIrOperGpr Src = new ShaderIrOperGpr(0x100 + Ch);

                ShaderIrOperGpr Dst = (Ch >> 1) != 0
                    ? GetOperGpr28(OpCode)
                    : GetOperGpr0(OpCode);

                Dst.Index += Ch & 1;

                if (Dst.Index >= ShaderIrOperGpr.ZRIndex)
                {
                    continue;
                }

                Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Src), OpCode));
            }
        }
Esempio n. 17
0
        private static void EmitAluBinaryF(
            ShaderIrBlock Block,
            long OpCode,
            ShaderOper Oper,
            ShaderIrInst Inst)
        {
            bool Nb = ((OpCode >> 45) & 1) != 0;
            bool Aa = ((OpCode >> 46) & 1) != 0;
            bool Na = ((OpCode >> 48) & 1) != 0;
            bool Ab = ((OpCode >> 49) & 1) != 0;
            bool Ad = ((OpCode >> 50) & 1) != 0;

            ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;

            if (Inst == ShaderIrInst.Fadd)
            {
                OperA = GetAluAbsNeg(OperA, Aa, Na);
            }

            switch (Oper)
            {
            case ShaderOper.CR:   OperB = GetOperCbuf34(OpCode); break;

            case ShaderOper.Immf: OperB = GetOperImmf19_20(OpCode); break;

            case ShaderOper.RR:   OperB = GetOperGpr20(OpCode); break;

            default: throw new ArgumentException(nameof(Oper));
            }

            OperB = GetAluAbsNeg(OperB, Ab, Nb);

            ShaderIrNode Op = new ShaderIrOp(Inst, OperA, OperB);

            Op = GetAluAbs(Op, Ad);

            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
        }
Esempio n. 18
0
        private static void EmitFmul(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
        {
            bool NegB = ((OpCode >> 48) & 1) != 0;

            ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;

            switch (Oper)
            {
            case ShaderOper.CR:   OperB = GetOperCbuf34(OpCode); break;

            case ShaderOper.Immf: OperB = GetOperImmf19_20(OpCode); break;

            case ShaderOper.RR:   OperB = GetOperGpr20(OpCode); break;

            default: throw new ArgumentException(nameof(Oper));
            }

            OperB = GetAluFneg(OperB, NegB);

            ShaderIrNode Op = new ShaderIrOp(ShaderIrInst.Fmul, OperA, OperB);

            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
        }
Esempio n. 19
0
        private static void EmitAluBinary(
            ShaderIrBlock block,
            long opCode,
            ShaderOper oper,
            ShaderIrInst inst)
        {
            ShaderIrNode operA = opCode.Gpr8(), operB;

            switch (oper)
            {
            case ShaderOper.Cr:  operB = opCode.Cbuf34();   break;

            case ShaderOper.Imm: operB = opCode.Imm19_20(); break;

            case ShaderOper.Rr:  operB = opCode.Gpr20();    break;

            default: throw new ArgumentException(nameof(oper));
            }

            ShaderIrNode op = new ShaderIrOp(inst, operA, operB);

            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op)));
        }
Esempio n. 20
0
        private static void EmitFmul(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
        {
            bool NegB = OpCode.Read(48);

            ShaderIrNode OperA = OpCode.Gpr8(), OperB;

            switch (Oper)
            {
            case ShaderOper.CR:   OperB = OpCode.Cbuf34();    break;

            case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;

            case ShaderOper.RR:   OperB = OpCode.Gpr20();     break;

            default: throw new ArgumentException(nameof(Oper));
            }

            OperB = GetAluFneg(OperB, NegB);

            ShaderIrNode Op = new ShaderIrOp(ShaderIrInst.Fmul, OperA, OperB);

            Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
        }
Esempio n. 21
0
        private static void EmitAluBinary(
            ShaderIrBlock Block,
            long OpCode,
            ShaderOper Oper,
            ShaderIrInst Inst)
        {
            ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;

            switch (Oper)
            {
            case ShaderOper.CR:  OperB = GetOperCbuf34(OpCode); break;

            case ShaderOper.Imm: OperB = GetOperImm19_20(OpCode); break;

            case ShaderOper.RR:  OperB = GetOperGpr20(OpCode); break;

            default: throw new ArgumentException(nameof(Oper));
            }

            ShaderIrNode Op = new ShaderIrOp(Inst, OperA, OperB);

            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
        }
Esempio n. 22
0
        private static void EmitFfma(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
        {
            bool NegB = OpCode.Read(48);
            bool NegC = OpCode.Read(49);
            bool Sat  = OpCode.Read(50);

            ShaderIrNode OperA = OpCode.Gpr8(), OperB, OperC;

            switch (Oper)
            {
            case ShaderOper.CR:   OperB = OpCode.Cbuf34();    break;

            case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;

            case ShaderOper.RC:   OperB = OpCode.Gpr39();     break;

            case ShaderOper.RR:   OperB = OpCode.Gpr20();     break;

            default: throw new ArgumentException(nameof(Oper));
            }

            OperB = GetAluFneg(OperB, NegB);

            if (Oper == ShaderOper.RC)
            {
                OperC = GetAluFneg(OpCode.Cbuf34(), NegC);
            }
            else
            {
                OperC = GetAluFneg(OpCode.Gpr39(), NegC);
            }

            ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Ffma, OperA, OperB, OperC);

            Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), GetAluFsat(Op, Sat))));
        }
Esempio n. 23
0
        private static void EmitFfma(ShaderIrBlock block, long opCode, ShaderOper oper)
        {
            bool negB = opCode.Read(48);
            bool negC = opCode.Read(49);
            bool sat  = opCode.Read(50);

            ShaderIrNode operA = opCode.Gpr8(), operB, operC;

            switch (oper)
            {
            case ShaderOper.Cr:   operB = opCode.Cbuf34();    break;

            case ShaderOper.Immf: operB = opCode.Immf19_20(); break;

            case ShaderOper.Rc:   operB = opCode.Gpr39();     break;

            case ShaderOper.Rr:   operB = opCode.Gpr20();     break;

            default: throw new ArgumentException(nameof(oper));
            }

            operB = GetAluFneg(operB, negB);

            if (oper == ShaderOper.Rc)
            {
                operC = GetAluFneg(opCode.Cbuf34(), negC);
            }
            else
            {
                operC = GetAluFneg(opCode.Gpr39(), negC);
            }

            ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Ffma, operA, operB, operC);

            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), GetAluFsat(op, sat))));
        }
Esempio n. 24
0
        public static ShaderIrBlock[] Decode(IGalMemory Memory, long Start)
        {
            Dictionary <long, ShaderIrBlock> Visited    = new Dictionary <long, ShaderIrBlock>();
            Dictionary <long, ShaderIrBlock> VisitedEnd = new Dictionary <long, ShaderIrBlock>();

            Queue <ShaderIrBlock> Blocks = new Queue <ShaderIrBlock>();

            ShaderIrBlock Enqueue(long Position, ShaderIrBlock Source = null)
            {
                if (!Visited.TryGetValue(Position, out ShaderIrBlock Output))
                {
                    Output = new ShaderIrBlock(Position);

                    Blocks.Enqueue(Output);

                    Visited.Add(Position, Output);
                }

                if (Source != null)
                {
                    Output.Sources.Add(Source);
                }

                return(Output);
            }

            ShaderIrBlock Entry = Enqueue(Start + HeaderSize);

            while (Blocks.Count > 0)
            {
                ShaderIrBlock Current = Blocks.Dequeue();

                FillBlock(Memory, Current, Start + HeaderSize);

                //Set child blocks. "Branch" is the block the branch instruction
                //points to (when taken), "Next" is the block at the next address,
                //executed when the branch is not taken. For Unconditional Branches
                //or end of shader, Next is null.
                if (Current.Nodes.Count > 0)
                {
                    ShaderIrNode LastNode = Current.GetLastNode();

                    ShaderIrOp Op = GetInnermostOp(LastNode);

                    if (Op?.Inst == ShaderIrInst.Bra)
                    {
                        int Offset = ((ShaderIrOperImm)Op.OperandA).Value;

                        long Target = Current.EndPosition + Offset;

                        Current.Branch = Enqueue(Target, Current);
                    }

                    if (NodeHasNext(LastNode))
                    {
                        Current.Next = Enqueue(Current.EndPosition);
                    }
                }

                //If we have on the graph two blocks with the same end position,
                //then we need to split the bigger block and have two small blocks,
                //the end position of the bigger "Current" block should then be == to
                //the position of the "Smaller" block.
                while (VisitedEnd.TryGetValue(Current.EndPosition, out ShaderIrBlock Smaller))
                {
                    if (Current.Position > Smaller.Position)
                    {
                        ShaderIrBlock Temp = Smaller;

                        Smaller = Current;
                        Current = Temp;
                    }

                    Current.EndPosition = Smaller.Position;
                    Current.Next        = Smaller;
                    Current.Branch      = null;

                    Current.Nodes.RemoveRange(
                        Current.Nodes.Count - Smaller.Nodes.Count,
                        Smaller.Nodes.Count);

                    VisitedEnd[Smaller.EndPosition] = Smaller;
                }

                VisitedEnd.Add(Current.EndPosition, Current);
            }

            //Make and sort Graph blocks array by position.
            ShaderIrBlock[] Graph = new ShaderIrBlock[Visited.Count];

            while (Visited.Count > 0)
            {
                ulong FirstPos = ulong.MaxValue;

                foreach (ShaderIrBlock Block in Visited.Values)
                {
                    if (FirstPos > (ulong)Block.Position)
                    {
                        FirstPos = (ulong)Block.Position;
                    }
                }

                ShaderIrBlock Current = Visited[(long)FirstPos];

                do
                {
                    Graph[Graph.Length - Visited.Count] = Current;

                    Visited.Remove(Current.Position);

                    Current = Current.Next;
                }while (Current != null);
            }

            return(Graph);
        }
Esempio n. 25
0
        private static void EmitSet(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper)
        {
            bool NegA = OpCode.Read(43);
            bool AbsB = OpCode.Read(44);
            bool NegB = OpCode.Read(53);
            bool AbsA = OpCode.Read(54);

            bool BoolFloat = OpCode.Read(IsFloat ? 52 : 44);

            ShaderIrNode OperA = OpCode.Gpr8(), OperB;

            switch (Oper)
            {
            case ShaderOper.CR:   OperB = OpCode.Cbuf34();    break;

            case ShaderOper.Imm:  OperB = OpCode.Imm19_20();  break;

            case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;

            case ShaderOper.RR:   OperB = OpCode.Gpr20();     break;

            default: throw new ArgumentException(nameof(Oper));
            }

            ShaderIrInst CmpInst;

            if (IsFloat)
            {
                OperA = GetAluFabsFneg(OperA, AbsA, NegA);
                OperB = GetAluFabsFneg(OperB, AbsB, NegB);

                CmpInst = OpCode.CmpF();
            }
            else
            {
                CmpInst = OpCode.Cmp();
            }

            ShaderIrOp Op = new ShaderIrOp(CmpInst, OperA, OperB);

            ShaderIrInst LopInst = OpCode.BLop45();

            ShaderIrOperPred PNode = OpCode.Pred39();

            ShaderIrNode Imm0, Imm1;

            if (BoolFloat)
            {
                Imm0 = new ShaderIrOperImmf(0);
                Imm1 = new ShaderIrOperImmf(1);
            }
            else
            {
                Imm0 = new ShaderIrOperImm(0);
                Imm1 = new ShaderIrOperImm(-1);
            }

            ShaderIrNode Asg0 = new ShaderIrAsg(OpCode.Gpr0(), Imm0);
            ShaderIrNode Asg1 = new ShaderIrAsg(OpCode.Gpr0(), Imm1);

            if (LopInst != ShaderIrInst.Band || !PNode.IsConst)
            {
                ShaderIrOp Op2 = new ShaderIrOp(LopInst, Op, PNode);

                Asg0 = new ShaderIrCond(Op2, Asg0, Not: true);
                Asg1 = new ShaderIrCond(Op2, Asg1, Not: false);
            }
            else
            {
                Asg0 = new ShaderIrCond(Op, Asg0, Not: true);
                Asg1 = new ShaderIrCond(Op, Asg1, Not: false);
            }

            Block.AddNode(OpCode.PredNode(Asg0));
            Block.AddNode(OpCode.PredNode(Asg1));
        }
Esempio n. 26
0
        private static void EmitMnmx(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper)
        {
            bool NegB = OpCode.Read(45);
            bool AbsA = OpCode.Read(46);
            bool NegA = OpCode.Read(48);
            bool AbsB = OpCode.Read(49);

            ShaderIrNode OperA = OpCode.Gpr8(), OperB;

            if (IsFloat)
            {
                OperA = GetAluFabsFneg(OperA, AbsA, NegA);
            }
            else
            {
                OperA = GetAluIabsIneg(OperA, AbsA, NegA);
            }

            switch (Oper)
            {
            case ShaderOper.CR:   OperB = OpCode.Cbuf34();    break;

            case ShaderOper.Imm:  OperB = OpCode.Imm19_20();  break;

            case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;

            case ShaderOper.RR:   OperB = OpCode.Gpr20();     break;

            default: throw new ArgumentException(nameof(Oper));
            }

            if (IsFloat)
            {
                OperB = GetAluFabsFneg(OperB, AbsB, NegB);
            }
            else
            {
                OperB = GetAluIabsIneg(OperB, AbsB, NegB);
            }

            ShaderIrOperPred Pred = OpCode.Pred39();

            ShaderIrOp Op;

            ShaderIrInst MaxInst = IsFloat ? ShaderIrInst.Fmax : ShaderIrInst.Max;
            ShaderIrInst MinInst = IsFloat ? ShaderIrInst.Fmin : ShaderIrInst.Min;

            if (Pred.IsConst)
            {
                bool IsMax = OpCode.Read(42);

                Op = new ShaderIrOp(IsMax
                    ? MaxInst
                    : MinInst, OperA, OperB);

                Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
            }
            else
            {
                ShaderIrNode PredN = OpCode.Pred39N();

                ShaderIrOp OpMax = new ShaderIrOp(MaxInst, OperA, OperB);
                ShaderIrOp OpMin = new ShaderIrOp(MinInst, OperA, OperB);

                ShaderIrAsg AsgMax = new ShaderIrAsg(OpCode.Gpr0(), OpMax);
                ShaderIrAsg AsgMin = new ShaderIrAsg(OpCode.Gpr0(), OpMin);

                Block.AddNode(OpCode.PredNode(new ShaderIrCond(PredN, AsgMax, Not: true)));
                Block.AddNode(OpCode.PredNode(new ShaderIrCond(PredN, AsgMin, Not: false)));
            }
        }
Esempio n. 27
0
        private static void EmitIadd3(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
        {
            int Mode = OpCode.Read(37, 3);

            bool Neg1 = OpCode.Read(51);
            bool Neg2 = OpCode.Read(50);
            bool Neg3 = OpCode.Read(49);

            int Height1 = OpCode.Read(35, 3);
            int Height2 = OpCode.Read(33, 3);
            int Height3 = OpCode.Read(31, 3);

            ShaderIrNode OperB;

            switch (Oper)
            {
            case ShaderOper.CR:  OperB = OpCode.Cbuf34();   break;

            case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;

            case ShaderOper.RR:  OperB = OpCode.Gpr20();    break;

            default: throw new ArgumentException(nameof(Oper));
            }

            ShaderIrNode ApplyHeight(ShaderIrNode Src, int Height)
            {
                if (Oper != ShaderOper.RR)
                {
                    return(Src);
                }

                switch (Height)
                {
                case 0: return(Src);

                case 1: return(new ShaderIrOp(ShaderIrInst.And, Src, new ShaderIrOperImm(0xffff)));

                case 2: return(new ShaderIrOp(ShaderIrInst.Lsr, Src, new ShaderIrOperImm(16)));

                default: throw new InvalidOperationException();
                }
            }

            ShaderIrNode Src1 = GetAluIneg(ApplyHeight(OpCode.Gpr8(), Height1), Neg1);
            ShaderIrNode Src2 = GetAluIneg(ApplyHeight(OperB, Height2), Neg2);
            ShaderIrNode Src3 = GetAluIneg(ApplyHeight(OpCode.Gpr39(), Height3), Neg3);

            ShaderIrOp Sum = new ShaderIrOp(ShaderIrInst.Add, Src1, Src2);

            if (Oper == ShaderOper.RR)
            {
                switch (Mode)
                {
                case 1: Sum = new ShaderIrOp(ShaderIrInst.Lsr, Sum, new ShaderIrOperImm(16)); break;

                case 2: Sum = new ShaderIrOp(ShaderIrInst.Lsl, Sum, new ShaderIrOperImm(16)); break;
                }
            }

            //Note: Here there should be a "+ 1" when carry flag is set
            //but since carry is mostly ignored by other instructions, it's excluded for now

            Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), new ShaderIrOp(ShaderIrInst.Add, Sum, Src3))));
        }
Esempio n. 28
0
        private static void EmitXmad(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
        {
            //TODO: Confirm SignAB/C, it is just a guess.
            //TODO: Implement Mode 3 (CSFU), what it does?
            bool SignAB = OpCode.Read(48);
            bool SignC  = OpCode.Read(49);
            bool HighB  = OpCode.Read(52);
            bool HighA  = OpCode.Read(53);

            int Mode = OpCode.Read(50, 7);

            ShaderIrNode OperA = OpCode.Gpr8(), OperB, OperC;

            ShaderIrOperImm Imm16  = new ShaderIrOperImm(16);
            ShaderIrOperImm ImmMsk = new ShaderIrOperImm(0xffff);

            ShaderIrInst ShiftAB = SignAB ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
            ShaderIrInst ShiftC  = SignC  ? ShaderIrInst.Asr : ShaderIrInst.Lsr;

            if (HighA)
            {
                OperA = new ShaderIrOp(ShiftAB, OperA, Imm16);
            }

            switch (Oper)
            {
            case ShaderOper.CR:  OperB = OpCode.Cbuf34();   break;

            case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;

            case ShaderOper.RC:  OperB = OpCode.Gpr39();    break;

            case ShaderOper.RR:  OperB = OpCode.Gpr20();    break;

            default: throw new ArgumentException(nameof(Oper));
            }

            bool ProductShiftLeft = false, Merge = false;

            if (Oper == ShaderOper.RC)
            {
                OperC = OpCode.Cbuf34();
            }
            else
            {
                OperC = OpCode.Gpr39();

                ProductShiftLeft = OpCode.Read(36);
                Merge            = OpCode.Read(37);
            }

            switch (Mode)
            {
            //CLO.
            case 1: OperC = ExtendTo32(OperC, SignC, 16); break;

            //CHI.
            case 2: OperC = new ShaderIrOp(ShiftC, OperC, Imm16); break;
            }

            ShaderIrNode OperBH = OperB;

            if (HighB)
            {
                OperBH = new ShaderIrOp(ShiftAB, OperBH, Imm16);
            }

            ShaderIrOp MulOp = new ShaderIrOp(ShaderIrInst.Mul, OperA, OperBH);

            if (ProductShiftLeft)
            {
                MulOp = new ShaderIrOp(ShaderIrInst.Lsl, MulOp, Imm16);
            }

            ShaderIrOp AddOp = new ShaderIrOp(ShaderIrInst.Add, MulOp, OperC);

            if (Merge)
            {
                AddOp = new ShaderIrOp(ShaderIrInst.And, AddOp, ImmMsk);
                OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);
                AddOp = new ShaderIrOp(ShaderIrInst.Or, AddOp, OperB);
            }

            if (Mode == 4)
            {
                OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);
                AddOp = new ShaderIrOp(ShaderIrInst.Or, AddOp, OperB);
            }

            Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), AddOp)));
        }
Esempio n. 29
0
        private static void EmitSetp(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper)
        {
            bool AbsA = OpCode.Read(7);
            bool NegP = OpCode.Read(42);
            bool NegA = OpCode.Read(43);
            bool AbsB = OpCode.Read(44);

            ShaderIrNode OperA = OpCode.Gpr8(), OperB;

            switch (Oper)
            {
            case ShaderOper.CR:   OperB = OpCode.Cbuf34();    break;

            case ShaderOper.Imm:  OperB = OpCode.Imm19_20();  break;

            case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;

            case ShaderOper.RR:   OperB = OpCode.Gpr20();     break;

            default: throw new ArgumentException(nameof(Oper));
            }

            ShaderIrInst CmpInst;

            if (IsFloat)
            {
                OperA = GetAluFabsFneg(OperA, AbsA, NegA);
                OperB = GetAluFabs(OperB, AbsB);

                CmpInst = OpCode.CmpF();
            }
            else
            {
                CmpInst = OpCode.Cmp();
            }

            ShaderIrOp Op = new ShaderIrOp(CmpInst, OperA, OperB);

            ShaderIrOperPred P0Node = OpCode.Pred3();
            ShaderIrOperPred P1Node = OpCode.Pred0();
            ShaderIrOperPred P2Node = OpCode.Pred39();

            Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op)));

            ShaderIrInst LopInst = OpCode.BLop45();

            if (LopInst == ShaderIrInst.Band && P1Node.IsConst && P2Node.IsConst)
            {
                return;
            }

            ShaderIrNode P2NNode = P2Node;

            if (NegP)
            {
                P2NNode = new ShaderIrOp(ShaderIrInst.Bnot, P2NNode);
            }

            Op = new ShaderIrOp(ShaderIrInst.Bnot, P0Node);

            Op = new ShaderIrOp(LopInst, Op, P2NNode);

            Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P1Node, Op)));

            Op = new ShaderIrOp(LopInst, P0Node, P2NNode);

            Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op)));
        }
Esempio n. 30
0
        private static void EmitI2i(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
        {
            IntType Type = GetIntType(OpCode);

            if (Type == IntType.U64 ||
                Type == IntType.S64)
            {
                //TODO: 64-bits support.
                //Note: GLSL doesn't support 64-bits integers.
                throw new NotImplementedException();
            }

            int Sel = (int)(OpCode >> 41) & 3;

            bool NegA = ((OpCode >> 45) & 1) != 0;
            bool AbsA = ((OpCode >> 49) & 1) != 0;
            bool SatA = ((OpCode >> 50) & 1) != 0;

            ShaderIrNode OperA;

            switch (Oper)
            {
            case ShaderOper.CR:   OperA = GetOperCbuf34(OpCode); break;

            case ShaderOper.Immf: OperA = GetOperImmf19_20(OpCode); break;

            case ShaderOper.RR:   OperA = GetOperGpr20(OpCode); break;

            default: throw new ArgumentException(nameof(Oper));
            }

            OperA = GetAluIabsIneg(OperA, AbsA, NegA);

            bool Signed = Type >= IntType.S8;

            int Shift = Sel * 8;

            int Size = 8 << ((int)Type & 3);

            if (Shift != 0)
            {
                OperA = new ShaderIrOp(ShaderIrInst.Asr, OperA, new ShaderIrOperImm(Shift));
            }

            if (Size < 32)
            {
                uint Mask = uint.MaxValue >> (32 - Size);

                if (SatA)
                {
                    uint CMin = 0;
                    uint CMax = Mask;

                    if (Signed)
                    {
                        uint HalfMask = Mask >> 1;

                        CMin -= HalfMask + 1;
                        CMax  = HalfMask;
                    }

                    ShaderIrOperImm IMin = new ShaderIrOperImm((int)CMin);
                    ShaderIrOperImm IMax = new ShaderIrOperImm((int)CMax);

                    OperA = new ShaderIrOp(Signed
                        ? ShaderIrInst.Clamps
                        : ShaderIrInst.Clampu, OperA, IMin, IMax);
                }
                else
                {
                    OperA = ExtendTo32(OperA, Signed, Size);
                }
            }

            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), OperA), OpCode));
        }