Пример #1
0
        private static void EmitIscadd(ShaderIrBlock block, long opCode, ShaderOper oper)
        {
            bool negB = opCode.Read(48);
            bool negA = opCode.Read(49);

            ShaderIrNode operA = opCode.Gpr8(), operB;

            ShaderIrOperImm scale = opCode.Imm5_39();

            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));
            }

            operA = GetAluIneg(operA, negA);
            operB = GetAluIneg(operB, negB);

            ShaderIrOp scaleOp = new ShaderIrOp(ShaderIrInst.Lsl, operA, scale);
            ShaderIrOp addOp   = new ShaderIrOp(ShaderIrInst.Add, operB, scaleOp);

            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), addOp)));
        }
Пример #2
0
        private static void EmitIscadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
        {
            bool NegB = OpCode.Read(48);
            bool NegA = OpCode.Read(49);

            ShaderIrNode OperA = OpCode.Gpr8(), OperB;

            ShaderIrOperImm Scale = OpCode.Imm5_39();

            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));
            }

            OperA = GetAluIneg(OperA, NegA);
            OperB = GetAluIneg(OperB, NegB);

            ShaderIrOp ScaleOp = new ShaderIrOp(ShaderIrInst.Lsl, OperA, Scale);
            ShaderIrOp AddOp   = new ShaderIrOp(ShaderIrInst.Add, OperB, ScaleOp);

            Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), AddOp)));
        }
Пример #3
0
        public static void Mov_S(ShaderIrBlock block, long opCode, int position)
        {
            block.AddNode(new ShaderIrCmnt("Stubbed."));

            //Zero is used as a special number to get a valid "0 * 0 + VertexIndex" in a GS
            ShaderIrNode source = new ShaderIrOperImm(0);

            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), source)));
        }
Пример #4
0
        public static void Mov_S(ShaderIrBlock Block, long OpCode, long Position)
        {
            Block.AddNode(new ShaderIrCmnt("Stubbed."));

            //Zero is used as a special number to get a valid "0 * 0 + VertexIndex" in a GS
            ShaderIrNode Source = new ShaderIrOperImm(0);

            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Source), OpCode));
        }
Пример #5
0
        private static void EmitBfe(ShaderIrBlock block, long opCode, ShaderOper oper)
        {
            //TODO: Handle the case where position + length
            //is greater than the word size, in this case the sign bit
            //needs to be replicated to fill the remaining space.
            bool negB = opCode.Read(48);
            bool negA = opCode.Read(49);

            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;

            bool signed = opCode.Read(48); //?

            if (operB is ShaderIrOperImm posLen)
            {
                int position = (posLen.Value >> 0) & 0xff;
                int length   = (posLen.Value >> 8) & 0xff;

                int lSh = 32 - (position + length);

                ShaderIrInst rightShift = signed
                    ? ShaderIrInst.Asr
                    : ShaderIrInst.Lsr;

                op = new ShaderIrOp(ShaderIrInst.Lsl, operA, new ShaderIrOperImm(lSh));
                op = new ShaderIrOp(rightShift, op, new ShaderIrOperImm(lSh + position));
            }
            else
            {
                ShaderIrOperImm shift = new ShaderIrOperImm(8);
                ShaderIrOperImm mask  = new ShaderIrOperImm(0xff);

                ShaderIrNode opPos, opLen;

                opPos = new ShaderIrOp(ShaderIrInst.And, operB, mask);
                opLen = new ShaderIrOp(ShaderIrInst.Lsr, operB, shift);
                opLen = new ShaderIrOp(ShaderIrInst.And, opLen, mask);

                op = new ShaderIrOp(ShaderIrInst.Lsr, operA, opPos);

                op = ExtendTo32(op, signed, opLen);
            }

            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op)));
        }
Пример #6
0
        private static void EmitBfe(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
        {
            //TODO: Handle the case where position + length
            //is greater than the word size, in this case the sign bit
            //needs to be replicated to fill the remaining space.
            bool NegB = OpCode.Read(48);
            bool NegA = OpCode.Read(49);

            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;

            bool Signed = OpCode.Read(48); //?

            if (OperB is ShaderIrOperImm PosLen)
            {
                int Position = (PosLen.Value >> 0) & 0xff;
                int Length   = (PosLen.Value >> 8) & 0xff;

                int LSh = 32 - (Position + Length);

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

                Op = new ShaderIrOp(ShaderIrInst.Lsl, OperA, new ShaderIrOperImm(LSh));
                Op = new ShaderIrOp(RightShift, Op, new ShaderIrOperImm(LSh + Position));
            }
            else
            {
                ShaderIrOperImm Shift = new ShaderIrOperImm(8);
                ShaderIrOperImm Mask  = new ShaderIrOperImm(0xff);

                ShaderIrNode OpPos, OpLen;

                OpPos = new ShaderIrOp(ShaderIrInst.And, OperB, Mask);
                OpLen = new ShaderIrOp(ShaderIrInst.Lsr, OperB, Shift);
                OpLen = new ShaderIrOp(ShaderIrInst.And, OpLen, Mask);

                Op = new ShaderIrOp(ShaderIrInst.Lsr, OperA, OpPos);

                Op = ExtendTo32(Op, Signed, OpLen);
            }

            Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
        }
Пример #7
0
        public static void Ssy(ShaderIrBlock block, long opCode, int position)
        {
            if ((opCode & 0x20) != 0)
            {
                //This reads the target offset from the constant buffer.
                //Almost impossible to support with GLSL.
                throw new NotImplementedException();
            }

            ShaderIrOperImm imm = new ShaderIrOperImm(position + opCode.Branch());

            block.AddNode(new ShaderIrOp(ShaderIrInst.Ssy, imm));
        }
Пример #8
0
        public static void Bra(ShaderIrBlock Block, long OpCode, int Position)
        {
            if ((OpCode & 0x20) != 0)
            {
                //This reads the target offset from the constant buffer.
                //Almost impossible to support with GLSL.
                throw new NotImplementedException();
            }

            ShaderIrOperImm Imm = new ShaderIrOperImm(Position + OpCode.Branch());

            Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Bra, Imm)));
        }
Пример #9
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);
        }
Пример #10
0
        public static void Bra(ShaderIrBlock Block, long OpCode, long Position)
        {
            if ((OpCode & 0x20) != 0)
            {
                //This reads the target offset from the constant buffer.
                //Almost impossible to support with GLSL.
                throw new NotImplementedException();
            }

            int Target = ((int)(OpCode >> 20) << 8) >> 8;

            ShaderIrOperImm Imm = new ShaderIrOperImm(Target);

            Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Bra, Imm), OpCode));
        }
Пример #11
0
        public static void Mov_I32(ShaderIrBlock Block, long OpCode, int Position)
        {
            ShaderIrOperImm Imm = OpCode.Imm32_20();

            Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Imm)));
        }
Пример #12
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)));
        }
Пример #13
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));
        }
Пример #14
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));
        }
Пример #15
0
        public static void Mov_I32(ShaderIrBlock Block, long OpCode, long Position)
        {
            ShaderIrOperImm Imm = GetOperImm32_20(OpCode);

            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode));
        }
Пример #16
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 = opCode.Read(41, 3);

            bool negA = opCode.Read(45);
            bool absA = opCode.Read(49);
            bool satA = opCode.Read(50);

            ShaderIrNode operA;

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

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

            case ShaderOper.Rr:   operA = opCode.Gpr20();     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 min = new ShaderIrOperImm((int)cMin);
                    ShaderIrOperImm max = new ShaderIrOperImm((int)cMax);

                    operA = new ShaderIrOp(signed
                        ? ShaderIrInst.Clamps
                        : ShaderIrInst.Clampu, operA, min, max);
                }
                else
                {
                    operA = ExtendTo32(operA, signed, size);
                }
            }

            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), operA)));
        }
Пример #17
0
        private static void EmitTld4(ShaderIrBlock block, long opCode, GalTextureTarget textureType, TextureInstructionSuffix textureInstructionSuffix, int chMask, int component, bool scalar)
        {
            ShaderIrOperGpr operA = opCode.Gpr8();
            ShaderIrOperGpr operB = opCode.Gpr20();
            ShaderIrOperImm operC = opCode.Imm13_36();

            ShaderIrOperGpr[] coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(textureType)];

            ShaderIrOperGpr offset       = null;
            ShaderIrOperGpr depthCompare = null;

            bool isArray = ImageUtils.IsArray(textureType);

            int operBIndex = 0;

            if (scalar)
            {
                int coordStartIndex = 0;

                if (isArray)
                {
                    coordStartIndex++;
                    coords[coords.Length - 1] = operB;
                }

                switch (coords.Length - coordStartIndex)
                {
                case 1:
                    coords[0] = opCode.Gpr8();

                    break;

                case 2:
                    coords[0]        = opCode.Gpr8();
                    coords[0].Index += coordStartIndex;

                    break;

                case 3:
                    coords[0]        = opCode.Gpr8();
                    coords[0].Index += coordStartIndex;

                    coords[1]        = opCode.Gpr8();
                    coords[1].Index += 1 + coordStartIndex;

                    break;

                default:
                    throw new NotSupportedException($"{coords.Length - coordStartIndex} coords textures aren't supported in TLD4S");
                }

                if (coords.Length - coordStartIndex != 1)
                {
                    coords[coords.Length - coordStartIndex - 1] = operB;
                    operBIndex++;
                }

                if (textureInstructionSuffix != TextureInstructionSuffix.None && textureType == GalTextureTarget.TwoD)
                {
                    coords[coords.Length - coordStartIndex - 1]        = opCode.Gpr8();
                    coords[coords.Length - coordStartIndex - 1].Index += coords.Length - coordStartIndex - 1;
                    operBIndex--;
                }
            }
            else
            {
                int indexExtraCoord = 0;

                if (isArray)
                {
                    indexExtraCoord++;

                    coords[coords.Length - 1] = opCode.Gpr8();
                }

                for (int index = 0; index < coords.Length - indexExtraCoord; index++)
                {
                    coords[index] = opCode.Gpr8();

                    coords[index].Index += index;

                    coords[index].Index += indexExtraCoord;

                    if (coords[index].Index > ShaderIrOperGpr.ZrIndex)
                    {
                        coords[index].Index = ShaderIrOperGpr.ZrIndex;
                    }
                }
            }

            if ((textureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0)
            {
                offset        = opCode.Gpr20();
                offset.Index += operBIndex;
                operBIndex++;
            }

            if ((textureInstructionSuffix & TextureInstructionSuffix.Dc) != 0)
            {
                depthCompare        = opCode.Gpr20();
                depthCompare.Index += operBIndex;
                operBIndex++;
            }

            coords = CoordsRegistersToTempRegisters(block, coords);

            int regInc = 0;

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

                ShaderIrOperGpr dst = opCode.Gpr0();

                dst.Index += regInc++;

                if (!dst.IsValidRegister || dst.IsConst)
                {
                    continue;
                }

                ShaderIrMetaTex meta = new ShaderIrMetaTex(ch, textureType, textureInstructionSuffix, coords)
                {
                    Component    = component,
                    Offset       = offset,
                    DepthCompare = depthCompare
                };

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

                block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, op)));
            }
        }
Пример #18
0
        public static void Mov_I32(ShaderIrBlock block, long opCode, int position)
        {
            ShaderIrOperImm imm = opCode.Imm32_20();

            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), imm)));
        }
Пример #19
0
        private static void EmitXmad(ShaderIrBlock block, long opCode, ShaderOper oper)
        {
            bool signedA = opCode.Read(48);
            bool signedB = 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;

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

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

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

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

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

            ShaderIrNode operB2 = operB;

            if (oper == ShaderOper.Imm)
            {
                int imm = ((ShaderIrOperImm)operB2).Value;

                if (!highB)
                {
                    imm <<= 16;
                }

                if (signedB)
                {
                    imm >>= 16;
                }
                else
                {
                    imm = (int)((uint)imm >> 16);
                }

                operB2 = new ShaderIrOperImm(imm);
            }

            ShaderIrOperImm imm16 = new ShaderIrOperImm(16);

            //If we are working with the lower 16-bits of the A/B operands,
            //we need to shift the lower 16-bits to the top 16-bits. Later,
            //they will be right shifted. For U16 types, this will be a logical
            //right shift, and for S16 types, a arithmetic right shift.
            if (!highA)
            {
                operA = new ShaderIrOp(ShaderIrInst.Lsl, operA, imm16);
            }

            if (!highB && oper != ShaderOper.Imm)
            {
                operB2 = new ShaderIrOp(ShaderIrInst.Lsl, operB2, imm16);
            }

            ShaderIrInst shiftA = signedA ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
            ShaderIrInst shiftB = signedB ? ShaderIrInst.Asr : ShaderIrInst.Lsr;

            operA = new ShaderIrOp(shiftA, operA, imm16);

            if (oper != ShaderOper.Imm)
            {
                operB2 = new ShaderIrOp(shiftB, operB2, imm16);
            }

            bool productShiftLeft = false;
            bool merge            = false;

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

                productShiftLeft = opCode.Read(36);
                merge            = opCode.Read(37);
            }

            ShaderIrOp mulOp = new ShaderIrOp(ShaderIrInst.Mul, operA, operB2);

            if (productShiftLeft)
            {
                mulOp = new ShaderIrOp(ShaderIrInst.Lsl, mulOp, imm16);
            }

            switch ((XmadMode)mode)
            {
            case XmadMode.Clo: operC = ExtendTo32(operC, signed: false, size: 16); break;

            case XmadMode.Chi: operC = new ShaderIrOp(ShaderIrInst.Lsr, operC, imm16); break;

            case XmadMode.Cbcc:
            {
                ShaderIrOp operBLsh16 = new ShaderIrOp(ShaderIrInst.Lsl, operB, imm16);

                operC = new ShaderIrOp(ShaderIrInst.Add, operC, operBLsh16);

                break;
            }

            case XmadMode.Csfu:
            {
                ShaderIrOperImm imm31 = new ShaderIrOperImm(31);

                ShaderIrOp signAdjustA = new ShaderIrOp(ShaderIrInst.Lsr, operA, imm31);
                ShaderIrOp signAdjustB = new ShaderIrOp(ShaderIrInst.Lsr, operB2, imm31);

                signAdjustA = new ShaderIrOp(ShaderIrInst.Lsl, signAdjustA, imm16);
                signAdjustB = new ShaderIrOp(ShaderIrInst.Lsl, signAdjustB, imm16);

                ShaderIrOp signAdjust = new ShaderIrOp(ShaderIrInst.Add, signAdjustA, signAdjustB);

                operC = new ShaderIrOp(ShaderIrInst.Sub, operC, signAdjust);

                break;
            }
            }

            ShaderIrOp addOp = new ShaderIrOp(ShaderIrInst.Add, mulOp, operC);

            if (merge)
            {
                ShaderIrOperImm imm16Mask = new ShaderIrOperImm(0xffff);

                addOp = new ShaderIrOp(ShaderIrInst.And, addOp, imm16Mask);
                operB = new ShaderIrOp(ShaderIrInst.Lsl, operB, imm16);
                addOp = new ShaderIrOp(ShaderIrInst.Or, addOp, operB);
            }

            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), addOp)));
        }
Пример #20
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));
        }
Пример #21
0
        private static void EmitXmad(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
        {
            bool SignedA = OpCode.Read(48);
            bool SignedB = 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;

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

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

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

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

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

            ShaderIrNode OperB2 = OperB;

            if (Oper == ShaderOper.Imm)
            {
                int Imm = ((ShaderIrOperImm)OperB2).Value;

                if (!HighB)
                {
                    Imm <<= 16;
                }

                if (SignedB)
                {
                    Imm >>= 16;
                }
                else
                {
                    Imm = (int)((uint)Imm >> 16);
                }

                OperB2 = new ShaderIrOperImm(Imm);
            }

            ShaderIrOperImm Imm16 = new ShaderIrOperImm(16);

            //If we are working with the lower 16-bits of the A/B operands,
            //we need to shift the lower 16-bits to the top 16-bits. Later,
            //they will be right shifted. For U16 types, this will be a logical
            //right shift, and for S16 types, a arithmetic right shift.
            if (!HighA)
            {
                OperA = new ShaderIrOp(ShaderIrInst.Lsl, OperA, Imm16);
            }

            if (!HighB && Oper != ShaderOper.Imm)
            {
                OperB2 = new ShaderIrOp(ShaderIrInst.Lsl, OperB2, Imm16);
            }

            ShaderIrInst ShiftA = SignedA ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
            ShaderIrInst ShiftB = SignedB ? ShaderIrInst.Asr : ShaderIrInst.Lsr;

            OperA = new ShaderIrOp(ShiftA, OperA, Imm16);

            if (Oper != ShaderOper.Imm)
            {
                OperB2 = new ShaderIrOp(ShiftB, OperB2, Imm16);
            }

            bool ProductShiftLeft = false;
            bool Merge            = false;

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

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

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

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

            switch ((XmadMode)Mode)
            {
            case XmadMode.Clo: OperC = ExtendTo32(OperC, Signed: false, Size: 16); break;

            case XmadMode.Chi: OperC = new ShaderIrOp(ShaderIrInst.Lsr, OperC, Imm16); break;

            case XmadMode.Cbcc:
            {
                ShaderIrOp OperBLsh16 = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);

                OperC = new ShaderIrOp(ShaderIrInst.Add, OperC, OperBLsh16);

                break;
            }

            case XmadMode.Csfu:
            {
                ShaderIrOperImm Imm31 = new ShaderIrOperImm(31);

                ShaderIrOp SignAdjustA = new ShaderIrOp(ShaderIrInst.Lsr, OperA, Imm31);
                ShaderIrOp SignAdjustB = new ShaderIrOp(ShaderIrInst.Lsr, OperB2, Imm31);

                SignAdjustA = new ShaderIrOp(ShaderIrInst.Lsl, SignAdjustA, Imm16);
                SignAdjustB = new ShaderIrOp(ShaderIrInst.Lsl, SignAdjustB, Imm16);

                ShaderIrOp SignAdjust = new ShaderIrOp(ShaderIrInst.Add, SignAdjustA, SignAdjustB);

                OperC = new ShaderIrOp(ShaderIrInst.Sub, OperC, SignAdjust);

                break;
            }
            }

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

            if (Merge)
            {
                ShaderIrOperImm Imm16Mask = new ShaderIrOperImm(0xffff);

                AddOp = new ShaderIrOp(ShaderIrInst.And, AddOp, Imm16Mask);
                OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);
                AddOp = new ShaderIrOp(ShaderIrInst.Or, AddOp, OperB);
            }

            Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), AddOp)));
        }