Esempio n. 1
0
        public static void Imnmx(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            bool isSignedInt = op.RawOpCode.Extract(48);

            Operand srcA = GetSrcA(context);
            Operand srcB = GetSrcB(context);

            Operand resMin = isSignedInt
                ? context.IMinimumS32(srcA, srcB)
                : context.IMinimumU32(srcA, srcB);

            Operand resMax = isSignedInt
                ? context.IMaximumS32(srcA, srcB)
                : context.IMaximumU32(srcA, srcB);

            Operand pred = GetPredicate39(context);

            Operand dest = GetDest(context);

            context.Copy(dest, context.ConditionalSelect(pred, resMin, resMax));

            SetZnFlags(context, dest, op.SetCondCode);

            // TODO: X flags.
        }
Esempio n. 2
0
        public static void Iscadd(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            bool negateA = false, negateB = false;

            if (!(op is OpCodeAluImm32))
            {
                negateB = op.RawOpCode.Extract(48);
                negateA = op.RawOpCode.Extract(49);
            }

            int shift = op is OpCodeAluImm32
                ? op.RawOpCode.Extract(53, 5)
                : op.RawOpCode.Extract(39, 5);

            Operand srcA = GetSrcA(context);
            Operand srcB = GetSrcB(context);

            srcA = context.ShiftLeft(srcA, Const(shift));

            srcA = context.INegate(srcA, negateA);
            srcB = context.INegate(srcB, negateB);

            Operand res = context.IAdd(srcA, srcB);

            SetIaddFlags(context, res, srcA, srcB, op.SetCondCode, false);

            context.Copy(GetDest(context), res);
        }
Esempio n. 3
0
        public static void Shl(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            bool isMasked = op.RawOpCode.Extract(39);

            Operand srcB = GetSrcB(context);

            if (isMasked)
            {
                srcB = context.BitwiseAnd(srcB, Const(0x1f));
            }

            Operand res = context.ShiftLeft(GetSrcA(context), srcB);

            if (!isMasked)
            {
                // Clamped shift value.
                Operand isLessThan32 = context.ICompareLessUnsigned(srcB, Const(32));

                res = context.ConditionalSelect(isLessThan32, res, Const(0));
            }

            // TODO: X, CC

            context.Copy(GetDest(context), res);
        }
Esempio n. 4
0
        public static void I2F(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            FPType dstType = (FPType)op.RawOpCode.Extract(8, 2);

            IntegerType srcType = (IntegerType)op.RawOpCode.Extract(10, 2);

            bool isSmallInt = srcType <= IntegerType.U16;

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

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

            if (isSmallInt)
            {
                int size = srcType == IntegerType.U16 ? 16 : 8;

                srcB = isSignedInt
                    ? context.BitfieldExtractS32(srcB, Const(op.ByteSelection * 8), Const(size))
                    : context.BitfieldExtractU32(srcB, Const(op.ByteSelection * 8), Const(size));
            }

            srcB = isSignedInt
                ? context.IConvertS32ToFP(srcB)
                : context.IConvertU32ToFP(srcB);

            WriteFP(context, dstType, srcB);

            // TODO: CC.
        }
Esempio n. 5
0
        public static void Iadd(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            bool negateA = false, negateB = false;

            if (!(op is OpCodeAluImm32))
            {
                negateB = op.RawOpCode.Extract(48);
                negateA = op.RawOpCode.Extract(49);
            }

            Operand srcA = context.INegate(GetSrcA(context), negateA);
            Operand srcB = context.INegate(GetSrcB(context), negateB);

            Operand res = context.IAdd(srcA, srcB);

            bool isSubtraction = negateA || negateB;

            if (op.Extended)
            {
                //Add carry, or subtract borrow.
                res = context.IAdd(res, isSubtraction
                    ? context.BitwiseNot(GetCF(context))
                    : context.BitwiseAnd(GetCF(context), Const(1)));
            }

            SetIaddFlags(context, res, srcA, srcB, op.SetCondCode, op.Extended, isSubtraction);

            context.Copy(GetDest(context), res);
        }
        public static void R2p(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            bool isCC  = op.RawOpCode.Extract(40);
            int  shift = op.RawOpCode.Extract(41, 2) * 8;

            Operand value = GetSrcA(context);
            Operand mask  = GetSrcB(context);

            Operand Test(Operand value, int bit)
            {
                return(context.ICompareNotEqual(context.BitwiseAnd(value, Const(1 << bit)), Const(0)));
            }

            if (isCC)
            {
                // TODO: Support Register to condition code flags copy.
                context.Config.PrintLog("R2P.CC not implemented.");
            }
            else
            {
                for (int bit = 0; bit < 7; bit++)
                {
                    Operand pred = Register(bit, RegisterType.Predicate);

                    Operand res = context.ConditionalSelect(Test(mask, bit), Test(value, bit + shift), pred);

                    context.Copy(pred, res);
                }
            }
        }
Esempio n. 7
0
        public static void Iadd(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            bool negateA = false, negateB = false;

            if (!(op is OpCodeAluImm32))
            {
                negateB = op.RawOpCode.Extract(48);
                negateA = op.RawOpCode.Extract(49);
            }
            else
            {
                // TODO: Other IADD32I variant without the negate.
                negateA = op.RawOpCode.Extract(56);
            }

            Operand srcA = context.INegate(GetSrcA(context), negateA);
            Operand srcB = context.INegate(GetSrcB(context), negateB);

            Operand res = context.IAdd(srcA, srcB);

            if (op.Extended)
            {
                res = context.IAdd(res, context.BitwiseAnd(GetCF(), Const(1)));
            }

            SetIaddFlags(context, res, srcA, srcB, op.SetCondCode, op.Extended);

            context.Copy(GetDest(context), res);
        }
Esempio n. 8
0
        public static void Bfe(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            bool isReverse = op.RawOpCode.Extract(40);
            bool isSigned  = op.RawOpCode.Extract(48);

            Operand srcA = GetSrcA(context);
            Operand srcB = GetSrcB(context);

            if (isReverse)
            {
                srcA = context.BitfieldReverse(srcA);
            }

            Operand position = context.BitwiseAnd(srcB, Const(0xff));

            Operand size = context.BitfieldExtractU32(srcB, Const(8), Const(8));

            Operand res = isSigned
                ? context.BitfieldExtractS32(srcA, position, size)
                : context.BitfieldExtractU32(srcA, position, size);

            context.Copy(GetDest(context), res);

            // TODO: CC, X, corner cases
        }
        public static void S2r(EmitterContext context)
        {
            // TODO: Better impl.
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            SystemRegister sysReg = (SystemRegister)op.RawOpCode.Extract(20, 8);

            Operand src;

            switch (sysReg)
            {
            case SystemRegister.LaneId: src = Attribute(AttributeConsts.LaneId); break;

            // TODO: Use value from Y direction GPU register.
            case SystemRegister.YDirection: src = ConstF(1); break;

            case SystemRegister.ThreadId:
            {
                Operand tidX = Attribute(AttributeConsts.ThreadIdX);
                Operand tidY = Attribute(AttributeConsts.ThreadIdY);
                Operand tidZ = Attribute(AttributeConsts.ThreadIdZ);

                tidY = context.ShiftLeft(tidY, Const(16));
                tidZ = context.ShiftLeft(tidZ, Const(26));

                src = context.BitwiseOr(tidX, context.BitwiseOr(tidY, tidZ));

                break;
            }

            case SystemRegister.ThreadIdX: src = Attribute(AttributeConsts.ThreadIdX); break;

            case SystemRegister.ThreadIdY: src = Attribute(AttributeConsts.ThreadIdY); break;

            case SystemRegister.ThreadIdZ: src = Attribute(AttributeConsts.ThreadIdZ); break;

            case SystemRegister.CtaIdX:    src = Attribute(AttributeConsts.CtaIdX);    break;

            case SystemRegister.CtaIdY:    src = Attribute(AttributeConsts.CtaIdY);    break;

            case SystemRegister.CtaIdZ:    src = Attribute(AttributeConsts.CtaIdZ);    break;

            case SystemRegister.EqMask:    src = Attribute(AttributeConsts.EqMask);    break;

            case SystemRegister.LtMask:    src = Attribute(AttributeConsts.LtMask);    break;

            case SystemRegister.LeMask:    src = Attribute(AttributeConsts.LeMask);    break;

            case SystemRegister.GtMask:    src = Attribute(AttributeConsts.GtMask);    break;

            case SystemRegister.GeMask:    src = Attribute(AttributeConsts.GeMask);    break;

            default: src = Const(0); break;
            }

            context.Copy(GetDest(context), src);
        }
Esempio n. 10
0
        public static void Clz(ArmEmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            Operand n = GetIntOrZR(context, op.Rn);

            Operand d = context.CountLeadingZeros(n);

            SetAluDOrZR(context, d);
        }
Esempio n. 11
0
        public static void I2I(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            IntegerType dstType = (IntegerType)op.RawOpCode.Extract(8, 2);
            IntegerType srcType = (IntegerType)op.RawOpCode.Extract(10, 2);

            if (srcType == IntegerType.U64 || dstType == IntegerType.U64)
            {
                context.Config.PrintLog("Invalid I2I encoding.");

                return;
            }

            bool srcIsSmallInt = srcType <= IntegerType.U16;

            bool dstIsSignedInt = op.RawOpCode.Extract(12);
            bool srcIsSignedInt = op.RawOpCode.Extract(13);
            bool negateB        = op.RawOpCode.Extract(45);
            bool absoluteB      = op.RawOpCode.Extract(49);

            Operand srcB = GetSrcB(context);

            if (srcIsSmallInt)
            {
                int size = srcType == IntegerType.U16 ? 16 : 8;

                srcB = srcIsSignedInt
                    ? context.BitfieldExtractS32(srcB, Const(op.ByteSelection * 8), Const(size))
                    : context.BitfieldExtractU32(srcB, Const(op.ByteSelection * 8), Const(size));
            }

            srcB = context.IAbsNeg(srcB, absoluteB, negateB);

            if (op.Saturate)
            {
                if (dstIsSignedInt)
                {
                    dstType |= IntegerType.S8;
                }

                int min = (int)GetIntMin(dstType);
                int max = (int)GetIntMax(dstType);

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

            context.Copy(GetDest(context), srcB);

            // TODO: CC.
        }
Esempio n. 12
0
        public static void Popc(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            bool invert = op.RawOpCode.Extract(40);

            Operand srcB = context.BitwiseNot(GetSrcB(context), invert);

            Operand res = context.BitCount(srcB);

            context.Copy(GetDest(context), res);
        }
Esempio n. 13
0
        public static void Sel(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            Operand pred = GetPredicate39(context);

            Operand srcA = GetSrcA(context);
            Operand srcB = GetSrcB(context);

            Operand res = context.ConditionalSelect(pred, srcA, srcB);

            context.Copy(GetDest(context), res);
        }
        public static void Fswzadd(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            int mask = op.RawOpCode.Extract(28, 8);

            Operand srcA = GetSrcA(context);
            Operand srcB = GetSrcB(context);

            Operand dest = GetDest(context);

            context.Copy(dest, context.FPSwizzleAdd(srcA, srcB, mask));

            SetFPZnFlags(context, dest, op.SetCondCode);
        }
Esempio n. 15
0
        public static void Shr(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            bool isMasked  = op.RawOpCode.Extract(39);
            bool isReverse = op.RawOpCode.Extract(40);
            bool isSigned  = op.RawOpCode.Extract(48);

            Operand srcA = GetSrcA(context);
            Operand srcB = GetSrcB(context);

            if (isReverse)
            {
                srcA = context.BitfieldReverse(srcA);
            }

            if (isMasked)
            {
                srcB = context.BitwiseAnd(srcB, Const(0x1f));
            }

            Operand res = isSigned
                ? context.ShiftRightS32(srcA, srcB)
                : context.ShiftRightU32(srcA, srcB);

            if (!isMasked)
            {
                // Clamped shift value.
                Operand resShiftBy32;

                if (isSigned)
                {
                    resShiftBy32 = context.ShiftRightS32(srcA, Const(31));
                }
                else
                {
                    resShiftBy32 = Const(0);
                }

                Operand isLessThan32 = context.ICompareLessUnsigned(srcB, Const(32));

                res = context.ConditionalSelect(isLessThan32, res, resShiftBy32);
            }

            // TODO: X, CC

            context.Copy(GetDest(context), res);
        }
Esempio n. 16
0
        public static void Bfi(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            Operand srcA = GetSrcA(context);
            Operand srcB = GetSrcB(context);
            Operand srcC = GetSrcC(context);

            Operand position = context.BitwiseAnd(srcB, Const(0xff));

            Operand size = context.BitfieldExtractU32(srcB, Const(8), Const(8));

            Operand res = context.BitfieldInsert(srcC, srcA, position, size);

            context.Copy(GetDest(context), res);
        }
Esempio n. 17
0
        public static void Rro(EmitterContext context)
        {
            // This is the range reduction operator,
            // we translate it as a simple move, as it
            // should be always followed by a matching
            // MUFU instruction.
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

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

            Operand srcB = GetSrcB(context);

            srcB = context.FPAbsNeg(srcB, absoluteB, negateB);

            context.Copy(GetDest(context), srcB);
        }
Esempio n. 18
0
        public static void Rev32(ArmEmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            Operand n = GetIntOrZR(context, op.Rn);

            if (op.RegisterSize == RegisterSize.Int32)
            {
                SetAluDOrZR(context, context.ByteSwap(n));
            }
            else
            {
                Operand d = context.Call(new _U64_U64(SoftFallback.ReverseBytes32_64), n);

                SetAluDOrZR(context, d);
            }
        }
Esempio n. 19
0
        public static void Lea_Hi(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            bool isReg = op is OpCodeAluReg;
            bool negateA;
            int  shift;

            if (isReg)
            {
                negateA = op.RawOpCode.Extract(37);
                shift   = op.RawOpCode.Extract(28, 5);
            }
            else
            {
                negateA = op.RawOpCode.Extract(56);
                shift   = op.RawOpCode.Extract(51, 5);
            }

            Operand srcA = GetSrcA(context);
            Operand srcB = GetSrcB(context);
            Operand srcC = GetSrcC(context);

            Operand aLow  = context.ShiftLeft(srcA, Const(shift));
            Operand aHigh = shift == 0 ? Const(0) : context.ShiftRightU32(srcA, Const(32 - shift));

            aHigh = context.BitwiseOr(aHigh, context.ShiftLeft(srcC, Const(shift)));

            if (negateA)
            {
                // Perform 64-bit negation by doing bitwise not of the value,
                // then adding 1 and carrying over from low to high.
                aLow  = context.BitwiseNot(aLow);
                aHigh = context.BitwiseNot(aHigh);

                aLow  = AddWithCarry(context, aLow, Const(1), out Operand aLowCOut);
                aHigh = context.IAdd(aHigh, aLowCOut);
            }

            Operand res = context.IAdd(aHigh, srcB);

            context.Copy(GetDest(context), res);

            // TODO: CC, X
        }
Esempio n. 20
0
        public static void Imad(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            bool signedA = context.CurrOp.RawOpCode.Extract(48);
            bool signedB = context.CurrOp.RawOpCode.Extract(53);
            bool high    = context.CurrOp.RawOpCode.Extract(54);

            Operand srcA = GetSrcA(context);
            Operand srcB = GetSrcB(context);
            Operand srcC = GetSrcC(context);

            Operand res;

            if (high)
            {
                if (signedA && signedB)
                {
                    res = context.MultiplyHighS32(srcA, srcB);
                }
                else
                {
                    res = context.MultiplyHighU32(srcA, srcB);

                    if (signedA)
                    {
                        res = context.IAdd(res, context.IMultiply(srcB, context.ShiftRightS32(srcA, Const(31))));
                    }
                    else if (signedB)
                    {
                        res = context.IAdd(res, context.IMultiply(srcA, context.ShiftRightS32(srcB, Const(31))));
                    }
                }
            }
            else
            {
                res = context.IMultiply(srcA, srcB);
            }

            res = context.IAdd(res, srcC);

            // TODO: CC, X, SAT, and more?

            context.Copy(GetDest(context), res);
        }
Esempio n. 21
0
        public static void Rev32(ArmEmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            Operand n = GetIntOrZR(context, op.Rn);
            Operand d;

            if (op.RegisterSize == RegisterSize.Int32)
            {
                d = context.ByteSwap(n);
            }
            else
            {
                d = EmitReverseBytes32_64Op(context, n);
            }

            SetAluDOrZR(context, d);
        }
Esempio n. 22
0
        public static void Rev16(ArmEmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            Operand n = GetIntOrZR(context, op.Rn);
            Operand d;

            if (op.RegisterSize == RegisterSize.Int32)
            {
                d = context.Call(new _U32_U32(SoftFallback.ReverseBytes16_32), n);
            }
            else
            {
                d = context.Call(new _U64_U64(SoftFallback.ReverseBytes16_64), n);
            }

            SetAluDOrZR(context, d);
        }
Esempio n. 23
0
        public static void Cls(ArmEmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            Operand n = GetIntOrZR(context, op.Rn);

            Operand nHigh = context.ShiftRightUI(n, Const(1));

            bool is32Bits = op.RegisterSize == RegisterSize.Int32;

            Operand mask = is32Bits ? Const(int.MaxValue) : Const(long.MaxValue);

            Operand nLow = context.BitwiseAnd(n, mask);

            Operand res = context.CountLeadingZeros(context.BitwiseExclusiveOr(nHigh, nLow));

            res = context.Subtract(res, Const(res.Type, 1));

            SetAluDOrZR(context, res);
        }
Esempio n. 24
0
        public static void Lea(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            bool negateA = op.RawOpCode.Extract(45);

            int shift = op.RawOpCode.Extract(39, 5);

            Operand srcA = GetSrcA(context);
            Operand srcB = GetSrcB(context);

            srcA = context.ShiftLeft(srcA, Const(shift));
            srcA = context.INegate(srcA, negateA);

            Operand res = context.IAdd(srcA, srcB);

            context.Copy(GetDest(context), res);

            // TODO: CC, X
        }
Esempio n. 25
0
        public static void Flo(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            bool invert     = op.RawOpCode.Extract(40);
            bool countZeros = op.RawOpCode.Extract(41);
            bool isSigned   = op.RawOpCode.Extract(48);

            Operand srcB = context.BitwiseNot(GetSrcB(context), invert);

            Operand res = isSigned
                ? context.FindFirstSetS32(srcB)
                : context.FindFirstSetU32(srcB);

            if (countZeros)
            {
                res = context.BitwiseExclusiveOr(res, Const(31));
            }

            context.Copy(GetDest(context), res);
        }
Esempio n. 26
0
        public static void Rev64(ArmEmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            SetAluDOrZR(context, context.ByteSwap(GetIntOrZR(context, op.Rn)));
        }
Esempio n. 27
0
        public static void Mov(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            context.Copy(GetDest(context), GetSrcB(context));
        }
Esempio n. 28
0
        public static void Iadd3(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            IntegerHalfPart partC = (IntegerHalfPart)op.RawOpCode.Extract(31, 2);
            IntegerHalfPart partB = (IntegerHalfPart)op.RawOpCode.Extract(33, 2);
            IntegerHalfPart partA = (IntegerHalfPart)op.RawOpCode.Extract(35, 2);

            IntegerShift mode = (IntegerShift)op.RawOpCode.Extract(37, 2);

            bool negateC = op.RawOpCode.Extract(49);
            bool negateB = op.RawOpCode.Extract(50);
            bool negateA = op.RawOpCode.Extract(51);

            Operand Extend(Operand src, IntegerHalfPart part)
            {
                if (!(op is OpCodeAluReg) || part == IntegerHalfPart.B32)
                {
                    return(src);
                }

                if (part == IntegerHalfPart.H0)
                {
                    return(context.BitwiseAnd(src, Const(0xffff)));
                }
                else if (part == IntegerHalfPart.H1)
                {
                    return(context.ShiftRightU32(src, Const(16)));
                }
                else
                {
                    // TODO: Warning.
                }

                return(src);
            }

            Operand srcA = context.INegate(Extend(GetSrcA(context), partA), negateA);
            Operand srcB = context.INegate(Extend(GetSrcB(context), partB), negateB);
            Operand srcC = context.INegate(Extend(GetSrcC(context), partC), negateC);

            Operand res = context.IAdd(srcA, srcB);

            if (op is OpCodeAluReg && mode != IntegerShift.NoShift)
            {
                if (mode == IntegerShift.ShiftLeft)
                {
                    res = context.ShiftLeft(res, Const(16));
                }
                else if (mode == IntegerShift.ShiftRight)
                {
                    res = context.ShiftRightU32(res, Const(16));
                }
                else
                {
                    // TODO: Warning.
                }
            }

            res = context.IAdd(res, srcC);

            context.Copy(GetDest(context), res);

            // TODO: CC, X, corner cases
        }
Esempio n. 29
0
        public static void Xmad(EmitterContext context)
        {
            OpCodeAlu op = (OpCodeAlu)context.CurrOp;

            bool signedA = context.CurrOp.RawOpCode.Extract(48);
            bool signedB = context.CurrOp.RawOpCode.Extract(49);
            bool highA   = context.CurrOp.RawOpCode.Extract(53);

            bool isReg = (op is OpCodeAluReg) && !(op is OpCodeAluRegCbuf);
            bool isImm = (op is OpCodeAluImm);

            XmadCMode mode = isReg || isImm
                ? (XmadCMode)context.CurrOp.RawOpCode.Extract(50, 3)
                : (XmadCMode)context.CurrOp.RawOpCode.Extract(50, 2);

            bool highB = false;

            if (isReg)
            {
                highB = context.CurrOp.RawOpCode.Extract(35);
            }
            else if (!isImm)
            {
                highB = context.CurrOp.RawOpCode.Extract(52);
            }

            Operand srcA = GetSrcA(context);
            Operand srcB = GetSrcB(context);
            Operand srcC = GetSrcC(context);

            // XMAD immediates are 16-bits unsigned integers.
            if (srcB.Type == OperandType.Constant)
            {
                srcB = Const(srcB.Value & 0xffff);
            }

            Operand Extend16To32(Operand src, bool high, bool signed)
            {
                if (signed && high)
                {
                    return(context.ShiftRightS32(src, Const(16)));
                }
                else if (signed)
                {
                    return(context.BitfieldExtractS32(src, Const(0), Const(16)));
                }
                else if (high)
                {
                    return(context.ShiftRightU32(src, Const(16)));
                }
                else
                {
                    return(context.BitwiseAnd(src, Const(0xffff)));
                }
            }

            srcA = Extend16To32(srcA, highA, signedA);
            srcB = Extend16To32(srcB, highB, signedB);

            bool productShiftLeft = false;
            bool merge            = false;

            if (op is OpCodeAluCbuf)
            {
                productShiftLeft = context.CurrOp.RawOpCode.Extract(55);
                merge            = context.CurrOp.RawOpCode.Extract(56);
            }
            else if (!(op is OpCodeAluRegCbuf))
            {
                productShiftLeft = context.CurrOp.RawOpCode.Extract(36);
                merge            = context.CurrOp.RawOpCode.Extract(37);
            }

            bool extended;

            if ((op is OpCodeAluReg) || (op is OpCodeAluImm))
            {
                extended = context.CurrOp.RawOpCode.Extract(38);
            }
            else
            {
                extended = context.CurrOp.RawOpCode.Extract(54);
            }

            Operand res = context.IMultiply(srcA, srcB);

            if (productShiftLeft)
            {
                res = context.ShiftLeft(res, Const(16));
            }

            switch (mode)
            {
            case XmadCMode.Cfull: break;

            case XmadCMode.Clo: srcC = Extend16To32(srcC, high: false, signed: false); break;

            case XmadCMode.Chi: srcC = Extend16To32(srcC, high: true, signed: false); break;

            case XmadCMode.Cbcc:
            {
                srcC = context.IAdd(srcC, context.ShiftLeft(GetSrcB(context), Const(16)));

                break;
            }

            case XmadCMode.Csfu:
            {
                Operand signAdjustA = context.ShiftLeft(context.ShiftRightU32(srcA, Const(31)), Const(16));
                Operand signAdjustB = context.ShiftLeft(context.ShiftRightU32(srcB, Const(31)), Const(16));

                srcC = context.ISubtract(srcC, context.IAdd(signAdjustA, signAdjustB));

                break;
            }

            default: /* TODO: Warning */ break;
            }

            Operand product = res;

            if (extended)
            {
                // Add with carry.
                res = context.IAdd(res, context.BitwiseAnd(GetCF(), Const(1)));
            }
            else
            {
                // Add (no carry in).
                res = context.IAdd(res, srcC);
            }

            SetIaddFlags(context, res, product, srcC, op.SetCondCode, extended);

            if (merge)
            {
                res = context.BitwiseAnd(res, Const(0xffff));
                res = context.BitwiseOr(res, context.ShiftLeft(GetSrcB(context), Const(16)));
            }

            context.Copy(GetDest(context), res);
        }