Ejemplo n.º 1
0
        public static void Mov(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            context.Copy(GetDest(context), GetSrcB(context));
        }
Ejemplo n.º 2
0
        public static void F2I(EmitterContext context)
        {
            OpCodeFArith op = (OpCodeFArith)context.CurrOp;

            IntegerType intType = (IntegerType)op.RawOpCode.Extract(8, 2);

            if (intType == IntegerType.U64)
            {
                context.Config.PrintLog("Unimplemented 64-bits F2I.");

                return;
            }

            bool isSmallInt = intType <= IntegerType.U16;

            FPType floatType = (FPType)op.RawOpCode.Extract(10, 2);

            bool isSignedInt = op.RawOpCode.Extract(12);
            bool negateB     = op.RawOpCode.Extract(45);
            bool absoluteB   = op.RawOpCode.Extract(49);

            if (isSignedInt)
            {
                intType |= IntegerType.S8;
            }

            Operand srcB = context.FPAbsNeg(GetSrcB(context, floatType), absoluteB, negateB);

            switch (op.RoundingMode)
            {
            case RoundingMode.ToNearest:
                srcB = context.FPRound(srcB);
                break;

            case RoundingMode.TowardsNegativeInfinity:
                srcB = context.FPFloor(srcB);
                break;

            case RoundingMode.TowardsPositiveInfinity:
                srcB = context.FPCeiling(srcB);
                break;

            case RoundingMode.TowardsZero:
                srcB = context.FPTruncate(srcB);
                break;
            }

            if (!isSignedInt)
            {
                // Negative float to uint cast is undefined, so we clamp
                // the value before conversion.
                srcB = context.FPMaximum(srcB, ConstF(0));
            }

            srcB = isSignedInt
                ? context.FPConvertToS32(srcB)
                : context.FPConvertToU32(srcB);

            if (isSmallInt)
            {
                int min = (int)GetIntMin(intType);
                int max = (int)GetIntMax(intType);

                srcB = isSignedInt
                    ? context.IClampS32(srcB, Const(min), Const(max))
                    : context.IClampU32(srcB, Const(min), Const(max));
            }

            Operand dest = GetDest(context);

            context.Copy(dest, srcB);

            // TODO: CC.
        }
Ejemplo n.º 3
0
 public static Operand GetDest(EmitterContext context)
 {
     return(Register(((IOpCodeRd)context.CurrOp).Rd));
 }
Ejemplo n.º 4
0
        public static Operand GetDest2(EmitterContext context)
        {
            Register rd = ((IOpCodeRd)context.CurrOp).Rd;

            return(Register(rd.Index | 1, rd.Type));
        }
Ejemplo n.º 5
0
 public static void Sts(EmitterContext context)
 {
     EmitStore(context, MemoryRegion.Shared);
 }
Ejemplo n.º 6
0
        public static Operand GetFromTruthTable(EmitterContext context, Operand srcA, Operand srcB, Operand srcC, int imm)
        {
            Operand expr = null;

            // Handle some simple cases, or cases where
            // the KMap would yield poor results (like XORs).
            if (imm == 0x96 || imm == 0x69)
            {
                // XOR (0x96) and XNOR (0x69).
                if (imm == 0x69)
                {
                    srcA = context.BitwiseNot(srcA);
                }

                expr = context.BitwiseExclusiveOr(srcA, srcB);
                expr = context.BitwiseExclusiveOr(expr, srcC);

                return(expr);
            }
            else if (imm == 0)
            {
                // Always false.
                return(Const(IrConsts.False));
            }
            else if (imm == 0xff)
            {
                // Always true.
                return(Const(IrConsts.True));
            }

            int map;

            // Encode into gray code.
            map  = ((imm >> 0) & 1) << 0;
            map |= ((imm >> 1) & 1) << 4;
            map |= ((imm >> 2) & 1) << 1;
            map |= ((imm >> 3) & 1) << 5;
            map |= ((imm >> 4) & 1) << 3;
            map |= ((imm >> 5) & 1) << 7;
            map |= ((imm >> 6) & 1) << 2;
            map |= ((imm >> 7) & 1) << 6;

            // Solve KMap, get sum of products.
            int visited = 0;

            for (int index = 0; index < 8 && visited != 0xff; index++)
            {
                if ((map & (1 << index)) == 0)
                {
                    continue;
                }

                int mask = 0;

                for (int mSize = 4; mSize != 0; mSize >>= 1)
                {
                    mask = RotateLeft4((1 << mSize) - 1, index & 3) << (index & 4);

                    if ((map & mask) == mask)
                    {
                        break;
                    }
                }

                // The mask should wrap, if we are on the high row, shift to low etc.
                int mask2 = (index & 4) != 0 ? mask >> 4 : mask << 4;

                if ((map & mask2) == mask2)
                {
                    mask |= mask2;
                }

                if ((mask & visited) == mask)
                {
                    continue;
                }

                bool notA = (mask & 0x33) != 0;
                bool notB = (mask & 0x99) != 0;
                bool notC = (mask & 0x0f) != 0;

                bool aChanges = (mask & 0xcc) != 0 && notA;
                bool bChanges = (mask & 0x66) != 0 && notB;
                bool cChanges = (mask & 0xf0) != 0 && notC;

                Operand localExpr = null;

                void And(Operand source)
                {
                    if (localExpr != null)
                    {
                        localExpr = context.BitwiseAnd(localExpr, source);
                    }
                    else
                    {
                        localExpr = source;
                    }
                }

                if (!aChanges)
                {
                    And(context.BitwiseNot(srcA, notA));
                }

                if (!bChanges)
                {
                    And(context.BitwiseNot(srcB, notB));
                }

                if (!cChanges)
                {
                    And(context.BitwiseNot(srcC, notC));
                }

                if (expr != null)
                {
                    expr = context.BitwiseOr(expr, localExpr);
                }
                else
                {
                    expr = localExpr;
                }

                visited |= mask;
            }

            return(expr);
        }
Ejemplo n.º 7
0
 public static void Depbar(EmitterContext context)
 {
 }
Ejemplo n.º 8
0
 public static void St(EmitterContext context)
 {
     EmitStore(context, MemoryRegion.Local);
 }
Ejemplo n.º 9
0
 public static Operand GetSrcA(EmitterContext context)
 {
     return(Register(((IOpCodeRa)context.CurrOp).Ra));
 }
Ejemplo n.º 10
0
 public static void Bra(EmitterContext context)
 {
     EmitBranch(context, context.CurrBlock.Branch.Address);
 }
Ejemplo n.º 11
0
        private static void Tex(EmitterContext context, TextureFlags flags)
        {
            OpCodeTexture op = (OpCodeTexture)context.CurrOp;

            bool isBindless = (flags & TextureFlags.Bindless) != 0;
            bool intCoords  = (flags & TextureFlags.IntCoords) != 0;

            if (op.Rd.IsRZ)
            {
                return;
            }

            int raIndex = op.Ra.Index;
            int rbIndex = op.Rb.Index;

            Operand Ra()
            {
                if (raIndex > RegisterConsts.RegisterZeroIndex)
                {
                    return(Const(0));
                }

                return(context.Copy(Register(raIndex++, RegisterType.Gpr)));
            }

            Operand Rb()
            {
                if (rbIndex > RegisterConsts.RegisterZeroIndex)
                {
                    return(Const(0));
                }

                return(context.Copy(Register(rbIndex++, RegisterType.Gpr)));
            }

            Operand arrayIndex = op.IsArray ? Ra() : null;

            List <Operand> sourcesList = new List <Operand>();

            if (isBindless)
            {
                sourcesList.Add(Rb());
            }

            TextureType type = GetTextureType(op.Dimensions);

            int coordsCount = type.GetCoordsCount();

            for (int index = 0; index < coordsCount; index++)
            {
                sourcesList.Add(Ra());
            }

            if (op.IsArray)
            {
                sourcesList.Add(arrayIndex);

                type |= TextureType.Array;
            }

            bool hasLod = op.LodMode > TextureLodMode.LodZero;

            Operand lodValue = hasLod ? Rb() : ConstF(0);

            Operand packedOffs = op.HasOffset ? Rb() : null;

            if (op.HasDepthCompare)
            {
                sourcesList.Add(Rb());

                type |= TextureType.Shadow;
            }

            if ((op.LodMode == TextureLodMode.LodZero ||
                 op.LodMode == TextureLodMode.LodLevel ||
                 op.LodMode == TextureLodMode.LodLevelA) && !op.IsMultisample)
            {
                sourcesList.Add(lodValue);

                flags |= TextureFlags.LodLevel;
            }

            if (op.HasOffset)
            {
                for (int index = 0; index < coordsCount; index++)
                {
                    sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * 4), Const(4)));
                }

                flags |= TextureFlags.Offset;
            }

            if (op.LodMode == TextureLodMode.LodBias ||
                op.LodMode == TextureLodMode.LodBiasA)
            {
                sourcesList.Add(lodValue);

                flags |= TextureFlags.LodBias;
            }

            if (op.IsMultisample)
            {
                sourcesList.Add(Rb());

                type |= TextureType.Multisample;
            }

            Operand[] sources = sourcesList.ToArray();

            int rdIndex = op.Rd.Index;

            Operand GetDest()
            {
                if (rdIndex > RegisterConsts.RegisterZeroIndex)
                {
                    return(Const(0));
                }

                return(Register(rdIndex++, RegisterType.Gpr));
            }

            int handle = !isBindless ? op.Immediate : 0;

            for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
            {
                if ((compMask & 1) != 0)
                {
                    Operand dest = GetDest();

                    TextureOperation operation = new TextureOperation(
                        Instruction.TextureSample,
                        type,
                        flags,
                        handle,
                        compIndex,
                        dest,
                        sources);

                    context.Add(operation);
                }
            }
        }
Ejemplo n.º 12
0
        private static void Txq(EmitterContext context, bool bindless)
        {
            OpCodeTex op = (OpCodeTex)context.CurrOp;

            if (op.Rd.IsRZ)
            {
                return;
            }

            TextureProperty property = (TextureProperty)op.RawOpCode.Extract(22, 6);

            // TODO: Validate and use property.
            Instruction inst = Instruction.TextureSize;

            TextureType type = TextureType.Texture2D;

            TextureFlags flags = bindless ? TextureFlags.Bindless : TextureFlags.None;

            int raIndex = op.Ra.Index;

            Operand Ra()
            {
                if (raIndex > RegisterConsts.RegisterZeroIndex)
                {
                    return(Const(0));
                }

                return(context.Copy(Register(raIndex++, RegisterType.Gpr)));
            }

            List <Operand> sourcesList = new List <Operand>();

            if (bindless)
            {
                sourcesList.Add(Ra());
            }

            sourcesList.Add(Ra());

            Operand[] sources = sourcesList.ToArray();

            int rdIndex = op.Rd.Index;

            Operand GetDest()
            {
                if (rdIndex > RegisterConsts.RegisterZeroIndex)
                {
                    return(Const(0));
                }

                return(Register(rdIndex++, RegisterType.Gpr));
            }

            int handle = !bindless ? op.Immediate : 0;

            for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
            {
                if ((compMask & 1) != 0)
                {
                    Operand dest = GetDest();

                    TextureOperation operation = new TextureOperation(
                        inst,
                        type,
                        flags,
                        handle,
                        compIndex,
                        dest,
                        sources);

                    context.Add(operation);
                }
            }
        }
Ejemplo n.º 13
0
 public static void Txq_B(EmitterContext context)
 {
     Txq(context, bindless: true);
 }
Ejemplo n.º 14
0
 public static void Txq(EmitterContext context)
 {
     Txq(context, bindless: false);
 }
Ejemplo n.º 15
0
 public static void Kil(EmitterContext context)
 {
     context.Discard();
 }
Ejemplo n.º 16
0
 public static void Lds(EmitterContext context)
 {
     EmitLoad(context, MemoryRegion.Shared);
 }
Ejemplo n.º 17
0
 public static void Nop(EmitterContext context)
 {
 }
Ejemplo n.º 18
0
 public static void Stg(EmitterContext context)
 {
     EmitStoreGlobal(context);
 }
Ejemplo n.º 19
0
 public static void Ssy(EmitterContext context)
 {
     EmitPbkOrSsy(context);
 }
Ejemplo n.º 20
0
        private static Operand EmitAtomicOp(
            EmitterContext context,
            Instruction mr,
            AtomicOp op,
            ReductionType type,
            Operand addrLow,
            Operand addrHigh,
            Operand value)
        {
            Operand res = Const(0);

            switch (op)
            {
            case AtomicOp.Add:
                if (type == ReductionType.S32 || type == ReductionType.U32)
                {
                    res = context.AtomicAdd(mr, addrLow, addrHigh, value);
                }
                else
                {
                    context.Config.GpuAccessor.Log($"Invalid reduction type: {type}.");
                }
                break;

            case AtomicOp.BitwiseAnd:
                if (type == ReductionType.S32 || type == ReductionType.U32)
                {
                    res = context.AtomicAnd(mr, addrLow, addrHigh, value);
                }
                else
                {
                    context.Config.GpuAccessor.Log($"Invalid reduction type: {type}.");
                }
                break;

            case AtomicOp.BitwiseExclusiveOr:
                if (type == ReductionType.S32 || type == ReductionType.U32)
                {
                    res = context.AtomicXor(mr, addrLow, addrHigh, value);
                }
                else
                {
                    context.Config.GpuAccessor.Log($"Invalid reduction type: {type}.");
                }
                break;

            case AtomicOp.BitwiseOr:
                if (type == ReductionType.S32 || type == ReductionType.U32)
                {
                    res = context.AtomicOr(mr, addrLow, addrHigh, value);
                }
                else
                {
                    context.Config.GpuAccessor.Log($"Invalid reduction type: {type}.");
                }
                break;

            case AtomicOp.Maximum:
                if (type == ReductionType.S32)
                {
                    res = context.AtomicMaxS32(mr, addrLow, addrHigh, value);
                }
                else if (type == ReductionType.U32)
                {
                    res = context.AtomicMaxU32(mr, addrLow, addrHigh, value);
                }
                else
                {
                    context.Config.GpuAccessor.Log($"Invalid reduction type: {type}.");
                }
                break;

            case AtomicOp.Minimum:
                if (type == ReductionType.S32)
                {
                    res = context.AtomicMinS32(mr, addrLow, addrHigh, value);
                }
                else if (type == ReductionType.U32)
                {
                    res = context.AtomicMinU32(mr, addrLow, addrHigh, value);
                }
                else
                {
                    context.Config.GpuAccessor.Log($"Invalid reduction type: {type}.");
                }
                break;
            }

            return(res);
        }
Ejemplo n.º 21
0
 public static void Sync(EmitterContext context)
 {
     EmitBrkOrSync(context);
 }
Ejemplo n.º 22
0
 public static Operand SignExtendTo32(EmitterContext context, Operand src, int srcBits)
 {
     return(context.BitfieldExtractS32(src, Const(0), Const(srcBits)));
 }
Ejemplo n.º 23
0
        public static void Al2p(EmitterContext context)
        {
            InstAl2p op = context.GetOp <InstAl2p>();

            context.Copy(GetDest(op.Dest), context.IAdd(GetSrcReg(context, op.SrcA), Const(op.Imm11)));
        }
Ejemplo n.º 24
0
        public static Operand ZeroExtendTo32(EmitterContext context, Operand src, int srcBits)
        {
            int mask = (int)(0xffffffffu >> (32 - srcBits));

            return(context.BitwiseAnd(src, Const(mask)));
        }
Ejemplo n.º 25
0
        public static void OutC(EmitterContext context)
        {
            InstOutC op = context.GetOp <InstOutC>();

            EmitOut(context, op.OutType.HasFlag(OutType.Emit), op.OutType.HasFlag(OutType.Cut));
        }
Ejemplo n.º 26
0
 public static void Mov(EmitterContext context)
 {
     context.Copy(GetDest(context), GetSrcB(context));
 }
Ejemplo n.º 27
0
 public static void Ld(EmitterContext context)
 {
     EmitLoad(context, MemoryRegion.Local);
 }
Ejemplo n.º 28
0
        private static void EmitF2I(
            EmitterContext context,
            DstFmt srcType,
            IDstFmt dstType,
            RoundMode2 roundingMode,
            Operand src,
            int rd,
            bool absolute,
            bool negate)
        {
            if (dstType == IDstFmt.U64)
            {
                context.Config.GpuAccessor.Log("Unimplemented 64-bits F2I.");
            }

            Instruction fpType = srcType.ToInstFPType();

            bool isSignedInt = dstType == IDstFmt.S16 || dstType == IDstFmt.S32 || dstType == IDstFmt.S64;
            bool isSmallInt  = dstType == IDstFmt.U16 || dstType == IDstFmt.S16;

            Operand srcB = context.FPAbsNeg(src, absolute, negate, fpType);

            srcB = roundingMode switch
            {
                RoundMode2.Round => context.FPRound(srcB, fpType),
                RoundMode2.Floor => context.FPFloor(srcB, fpType),
                RoundMode2.Ceil => context.FPCeiling(srcB, fpType),
                RoundMode2.Trunc => context.FPTruncate(srcB, fpType),
                _ => srcB
            };

            if (!isSignedInt)
            {
                // Negative float to uint cast is undefined, so we clamp the value before conversion.
                Operand c0 = srcType == DstFmt.F64 ? context.PackDouble2x32(0.0) : ConstF(0);

                srcB = context.FPMaximum(srcB, c0, fpType);
            }

            if (srcType == DstFmt.F64)
            {
                srcB = isSignedInt
                    ? context.FP64ConvertToS32(srcB)
                    : context.FP64ConvertToU32(srcB);
            }
            else
            {
                srcB = isSignedInt
                    ? context.FP32ConvertToS32(srcB)
                    : context.FP32ConvertToU32(srcB);
            }

            if (isSmallInt)
            {
                int min = (int)GetIntMin(dstType);
                int max = (int)GetIntMax(dstType);

                srcB = isSignedInt
                    ? context.IClampS32(srcB, Const(min), Const(max))
                    : context.IClampU32(srcB, Const(min), Const(max));
            }

            Operand dest = GetDest(rd);

            context.Copy(dest, srcB);

            // TODO: CC.
        }
Ejemplo n.º 29
0
 public static void Ldg(EmitterContext context)
 {
     EmitLoadGlobal(context);
 }
Ejemplo n.º 30
0
 public abstract void EmitObject(LogicalObject obj, EmitterContext context);
Ejemplo n.º 31
0
        public static void Texs(EmitterContext context)
        {
            OpCodeTextureScalar op = (OpCodeTextureScalar)context.CurrOp;

            if (op.Rd0.IsRZ && op.Rd1.IsRZ)
            {
                return;
            }

            List <Operand> sourcesList = new List <Operand>();

            int raIndex = op.Ra.Index;
            int rbIndex = op.Rb.Index;

            Operand Ra()
            {
                if (raIndex > RegisterConsts.RegisterZeroIndex)
                {
                    return(Const(0));
                }

                return(context.Copy(Register(raIndex++, RegisterType.Gpr)));
            }

            Operand Rb()
            {
                if (rbIndex > RegisterConsts.RegisterZeroIndex)
                {
                    return(Const(0));
                }

                return(context.Copy(Register(rbIndex++, RegisterType.Gpr)));
            }

            void AddTextureOffset(int coordsCount, int stride, int size)
            {
                Operand packedOffs = Rb();

                for (int index = 0; index < coordsCount; index++)
                {
                    sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * stride), Const(size)));
                }
            }

            TextureType  type;
            TextureFlags flags;

            if (op is OpCodeTexs texsOp)
            {
                type  = GetTextureType(texsOp.Type);
                flags = GetTextureFlags(texsOp.Type);

                if ((type & TextureType.Array) != 0)
                {
                    Operand arrayIndex = Ra();

                    sourcesList.Add(Ra());
                    sourcesList.Add(Rb());

                    sourcesList.Add(arrayIndex);

                    if ((type & TextureType.Shadow) != 0)
                    {
                        sourcesList.Add(Rb());
                    }

                    if ((flags & TextureFlags.LodLevel) != 0)
                    {
                        sourcesList.Add(ConstF(0));
                    }
                }
                else
                {
                    switch (texsOp.Type)
                    {
                    case TextureScalarType.Texture1DLodZero:
                        sourcesList.Add(Ra());
                        break;

                    case TextureScalarType.Texture2D:
                        sourcesList.Add(Ra());
                        sourcesList.Add(Rb());
                        break;

                    case TextureScalarType.Texture2DLodZero:
                        sourcesList.Add(Ra());
                        sourcesList.Add(Rb());
                        sourcesList.Add(ConstF(0));
                        break;

                    case TextureScalarType.Texture2DLodLevel:
                    case TextureScalarType.Texture2DDepthCompare:
                    case TextureScalarType.Texture3D:
                    case TextureScalarType.TextureCube:
                        sourcesList.Add(Ra());
                        sourcesList.Add(Ra());
                        sourcesList.Add(Rb());
                        break;

                    case TextureScalarType.Texture2DLodZeroDepthCompare:
                    case TextureScalarType.Texture3DLodZero:
                        sourcesList.Add(Ra());
                        sourcesList.Add(Ra());
                        sourcesList.Add(Rb());
                        sourcesList.Add(ConstF(0));
                        break;

                    case TextureScalarType.Texture2DLodLevelDepthCompare:
                    case TextureScalarType.TextureCubeLodLevel:
                        sourcesList.Add(Ra());
                        sourcesList.Add(Ra());
                        sourcesList.Add(Rb());
                        sourcesList.Add(Rb());
                        break;
                    }
                }
            }
            else if (op is OpCodeTlds tldsOp)
            {
                type  = GetTextureType(tldsOp.Type);
                flags = GetTextureFlags(tldsOp.Type) | TextureFlags.IntCoords;

                switch (tldsOp.Type)
                {
                case TexelLoadScalarType.Texture1DLodZero:
                    sourcesList.Add(Ra());
                    sourcesList.Add(Const(0));
                    break;

                case TexelLoadScalarType.Texture1DLodLevel:
                    sourcesList.Add(Ra());
                    sourcesList.Add(Rb());
                    break;

                case TexelLoadScalarType.Texture2DLodZero:
                    sourcesList.Add(Ra());
                    sourcesList.Add(Rb());
                    sourcesList.Add(Const(0));
                    break;

                case TexelLoadScalarType.Texture2DLodZeroOffset:
                    sourcesList.Add(Ra());
                    sourcesList.Add(Ra());
                    sourcesList.Add(Const(0));
                    break;

                case TexelLoadScalarType.Texture2DLodZeroMultisample:
                case TexelLoadScalarType.Texture2DLodLevel:
                case TexelLoadScalarType.Texture2DLodLevelOffset:
                    sourcesList.Add(Ra());
                    sourcesList.Add(Ra());
                    sourcesList.Add(Rb());
                    break;

                case TexelLoadScalarType.Texture3DLodZero:
                    sourcesList.Add(Ra());
                    sourcesList.Add(Ra());
                    sourcesList.Add(Rb());
                    sourcesList.Add(Const(0));
                    break;

                case TexelLoadScalarType.Texture2DArrayLodZero:
                    sourcesList.Add(Rb());
                    sourcesList.Add(Rb());
                    sourcesList.Add(Ra());
                    sourcesList.Add(Const(0));
                    break;
                }

                if ((flags & TextureFlags.Offset) != 0)
                {
                    AddTextureOffset(type.GetCoordsCount(), 4, 4);
                }
            }
            else if (op is OpCodeTld4s tld4sOp)
            {
                if (!(tld4sOp.HasDepthCompare || tld4sOp.HasOffset))
                {
                    sourcesList.Add(Ra());
                    sourcesList.Add(Rb());
                }
                else
                {
                    sourcesList.Add(Ra());
                    sourcesList.Add(Ra());
                }

                type  = TextureType.Texture2D;
                flags = TextureFlags.Gather;

                if (tld4sOp.HasDepthCompare)
                {
                    sourcesList.Add(Rb());

                    type |= TextureType.Shadow;
                }

                if (tld4sOp.HasOffset)
                {
                    AddTextureOffset(type.GetCoordsCount(), 8, 6);

                    flags |= TextureFlags.Offset;
                }

                sourcesList.Add(Const(tld4sOp.GatherCompIndex));
            }
            else
            {
                throw new InvalidOperationException($"Invalid opcode type \"{op.GetType().Name}\".");
            }

            Operand[] sources = sourcesList.ToArray();

            Operand[] rd0 = new Operand[2] {
                ConstF(0), ConstF(0)
            };
            Operand[] rd1 = new Operand[2] {
                ConstF(0), ConstF(0)
            };

            int destIncrement = 0;

            Operand GetDest()
            {
                int high = destIncrement >> 1;
                int low  = destIncrement & 1;

                destIncrement++;

                if (op.IsFp16)
                {
                    return(high != 0
                        ? (rd1[low] = Local())
                        : (rd0[low] = Local()));
                }
                else
                {
                    int rdIndex = high != 0 ? op.Rd1.Index : op.Rd0.Index;

                    if (rdIndex < RegisterConsts.RegisterZeroIndex)
                    {
                        rdIndex += low;
                    }

                    return(Register(rdIndex, RegisterType.Gpr));
                }
            }

            int handle = op.Immediate;

            for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
            {
                if ((compMask & 1) != 0)
                {
                    Operand dest = GetDest();

                    TextureOperation operation = new TextureOperation(
                        Instruction.TextureSample,
                        type,
                        flags,
                        handle,
                        compIndex,
                        dest,
                        sources);

                    context.Add(operation);
                }
            }

            if (op.IsFp16)
            {
                context.Copy(Register(op.Rd0), context.PackHalf2x16(rd0[0], rd0[1]));
                context.Copy(Register(op.Rd1), context.PackHalf2x16(rd1[0], rd1[1]));
            }
        }