Example #1
0
        public static void Fswzadd(EmitterContext context)
        {
            InstFswzadd op = context.GetOp <InstFswzadd>();

            Operand srcA = GetSrcReg(context, op.SrcA);
            Operand srcB = GetSrcReg(context, op.SrcB);
            Operand dest = GetDest(op.Dest);

            context.Copy(dest, context.FPSwizzleAdd(srcA, srcB, op.PnWord));

            InstEmitAluHelper.SetFPZnFlags(context, dest, op.WriteCC);
        }
Example #2
0
        public static void Vmad(EmitterContext context)
        {
            InstVmad op = context.GetOp <InstVmad>();

            bool aSigned = (op.ASelect & VectorSelect.S8B0) != 0;
            bool bSigned = (op.BSelect & VectorSelect.S8B0) != 0;

            Operand srcA = InstEmitAluHelper.Extend(context, GetSrcReg(context, op.SrcA), op.ASelect);
            Operand srcC = context.INegate(GetSrcReg(context, op.SrcC), op.AvgMode == AvgMode.NegB);
            Operand srcB;

            if (op.BVideo)
            {
                srcB = InstEmitAluHelper.Extend(context, GetSrcReg(context, op.SrcB), op.BSelect);
            }
            else
            {
                int imm = op.Imm16;

                if (bSigned)
                {
                    imm = (imm << 16) >> 16;
                }

                srcB = Const(imm);
            }

            Operand productLow = context.IMultiply(srcA, srcB);
            Operand productHigh;

            if (aSigned == bSigned)
            {
                productHigh = aSigned
                    ? context.MultiplyHighS32(srcA, srcB)
                    : context.MultiplyHighU32(srcA, srcB);
            }
            else
            {
                Operand temp = aSigned
                    ? context.IMultiply(srcB, context.ShiftRightS32(srcA, Const(31)))
                    : context.IMultiply(srcA, context.ShiftRightS32(srcB, Const(31)));

                productHigh = context.IAdd(temp, context.MultiplyHighU32(srcA, srcB));
            }

            if (op.AvgMode == AvgMode.NegA)
            {
                (productLow, productHigh) = InstEmitAluHelper.NegateLong(context, productLow, productHigh);
            }

            Operand resLow  = InstEmitAluHelper.AddWithCarry(context, productLow, srcC, out Operand sumCarry);
            Operand resHigh = context.IAdd(productHigh, sumCarry);

            if (op.AvgMode == AvgMode.PlusOne)
            {
                resLow  = InstEmitAluHelper.AddWithCarry(context, resLow, Const(1), out Operand poCarry);
                resHigh = context.IAdd(resHigh, poCarry);
            }

            bool resSigned = op.ASelect == VectorSelect.S32 ||
                             op.BSelect == VectorSelect.S32 ||
                             op.AvgMode == AvgMode.NegB ||
                             op.AvgMode == AvgMode.NegA;

            int shift = op.VideoScale switch
            {
                VideoScale.Shr7 => 7,
                VideoScale.Shr15 => 15,
                _ => 0
            };

            if (shift != 0)
            {
                // Low = (Low >> Shift) | (High << (32 - Shift))
                // High >>= Shift
                resLow  = context.ShiftRightU32(resLow, Const(shift));
                resLow  = context.BitwiseOr(resLow, context.ShiftLeft(resHigh, Const(32 - shift)));
                resHigh = resSigned
                    ? context.ShiftRightS32(resHigh, Const(shift))
                    : context.ShiftRightU32(resHigh, Const(shift));
            }

            Operand res = resLow;

            if (op.Sat)
            {
                Operand sign = context.ShiftRightS32(resHigh, Const(31));

                if (resSigned)
                {
                    Operand overflow   = context.ICompareNotEqual(resHigh, context.ShiftRightS32(resLow, Const(31)));
                    Operand clampValue = context.ConditionalSelect(sign, Const(int.MinValue), Const(int.MaxValue));
                    res = context.ConditionalSelect(overflow, clampValue, resLow);
                }
                else
                {
                    Operand overflow = context.ICompareNotEqual(resHigh, Const(0));
                    res = context.ConditionalSelect(overflow, context.BitwiseNot(sign), resLow);
                }
            }

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

            // TODO: CC.
        }
    }
Example #3
0
        public static void Vsetp(EmitterContext context)
        {
            InstVsetp op = context.GetOp <InstVsetp>();

            Operand srcA = Extend(context, GetSrcReg(context, op.SrcA), op.ASelect);

            Operand srcB;

            if (op.BVideo)
            {
                srcB = Extend(context, GetSrcReg(context, op.SrcB), op.BSelect);
            }
            else
            {
                int imm = op.Imm16;

                if ((op.BSelect & VectorSelect.S8B0) != 0)
                {
                    imm = (imm << 16) >> 16;
                }

                srcB = Const(imm);
            }

            Operand p0Res;

            bool signedA = (op.ASelect & VectorSelect.S8B0) != 0;
            bool signedB = (op.BSelect & VectorSelect.S8B0) != 0;

            if (signedA != signedB)
            {
                bool a32 = (op.ASelect & ~VectorSelect.S8B0) == VectorSelect.U32;
                bool b32 = (op.BSelect & ~VectorSelect.S8B0) == VectorSelect.U32;

                if (!a32 && !b32)
                {
                    // Both values are extended small integer and can always fit in a S32, just do a signed comparison.
                    p0Res = GetIntComparison(context, op.VComp, srcA, srcB, isSigned: true, extended: false);
                }
                else
                {
                    // TODO: Mismatching sign case.
                    p0Res = Const(0);
                }
            }
            else
            {
                // Sign matches, just do a regular comparison.
                p0Res = GetIntComparison(context, op.VComp, srcA, srcB, signedA, extended: false);
            }

            Operand p1Res = context.BitwiseNot(p0Res);

            Operand pred = GetPredicate(context, op.SrcPred, op.SrcPredInv);

            p0Res = InstEmitAluHelper.GetPredLogicalOp(context, op.BoolOp, p0Res, pred);
            p1Res = InstEmitAluHelper.GetPredLogicalOp(context, op.BoolOp, p1Res, pred);

            context.Copy(Register(op.DestPred, RegisterType.Predicate), p0Res);
            context.Copy(Register(op.DestPredInv, RegisterType.Predicate), p1Res);
        }
Example #4
0
        private static void EmitShf(
            EmitterContext context,
            MaxShift maxShift,
            Operand srcA,
            Operand srcB,
            Operand srcC,
            int rd,
            bool mask,
            bool left,
            bool writeCC)
        {
            bool isLongShift   = maxShift == MaxShift.U64 || maxShift == MaxShift.S64;
            bool signedShift   = maxShift == MaxShift.S64;
            int  maxShiftConst = isLongShift ? 64 : 32;

            if (mask)
            {
                srcB = context.BitwiseAnd(srcB, Const(maxShiftConst - 1));
            }

            Operand res;

            if (left)
            {
                // res = (C << B) | (A >> (32 - B))
                res = context.ShiftLeft(srcC, srcB);
                res = context.BitwiseOr(res, context.ShiftRightU32(srcA, context.ISubtract(Const(32), srcB)));

                if (isLongShift)
                {
                    // res = B >= 32 ? A << (B - 32) : res
                    Operand lowerShift = context.ShiftLeft(srcA, context.ISubtract(srcB, Const(32)));

                    Operand shiftGreaterThan31 = context.ICompareGreaterOrEqualUnsigned(srcB, Const(32));
                    res = context.ConditionalSelect(shiftGreaterThan31, lowerShift, res);
                }
            }
            else
            {
                // res = (A >> B) | (C << (32 - B))
                res = context.ShiftRightU32(srcA, srcB);
                res = context.BitwiseOr(res, context.ShiftLeft(srcC, context.ISubtract(Const(32), srcB)));

                if (isLongShift)
                {
                    // res = B >= 32 ? C >> (B - 32) : res
                    Operand upperShift = signedShift
                        ? context.ShiftRightS32(srcC, context.ISubtract(srcB, Const(32)))
                        : context.ShiftRightU32(srcC, context.ISubtract(srcB, Const(32)));

                    Operand shiftGreaterThan31 = context.ICompareGreaterOrEqualUnsigned(srcB, Const(32));
                    res = context.ConditionalSelect(shiftGreaterThan31, upperShift, res);
                }
            }

            if (!mask)
            {
                // Clamped shift value.
                Operand isLessThanMax = context.ICompareLessUnsigned(srcB, Const(maxShiftConst));

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

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

            if (writeCC)
            {
                InstEmitAluHelper.SetZnFlags(context, res, writeCC);
            }

            // TODO: X.
        }
Example #5
0
        public static void Vmnmx(EmitterContext context)
        {
            InstVmnmx op = context.GetOp <InstVmnmx>();

            Operand srcA = InstEmitAluHelper.Extend(context, GetSrcReg(context, op.SrcA), op.ASelect);
            Operand srcC = GetSrcReg(context, op.SrcC);
            Operand srcB;

            if (op.BVideo)
            {
                srcB = InstEmitAluHelper.Extend(context, GetSrcReg(context, op.SrcB), op.BSelect);
            }
            else
            {
                int imm = op.Imm16;

                if ((op.BSelect & VectorSelect.S8B0) != 0)
                {
                    imm = (imm << 16) >> 16;
                }

                srcB = Const(imm);
            }

            Operand res;

            bool resSigned;

            if ((op.ASelect & VectorSelect.S8B0) != (op.BSelect & VectorSelect.S8B0))
            {
                // Signedness is different, but for max, result will always fit a U32,
                // since one of the inputs can't be negative, and the result is the one
                // with highest value. For min, it will always fit on a S32, since
                // one of the input can't be greater than INT_MAX and we want the lowest value.
                resSigned = !op.Mn;

                res = op.Mn ? context.IMaximumU32(srcA, srcB) : context.IMinimumS32(srcA, srcB);

                if ((op.ASelect & VectorSelect.S8B0) != 0)
                {
                    Operand isBGtIntMax = context.ICompareLess(srcB, Const(0));

                    res = context.ConditionalSelect(isBGtIntMax, srcB, res);
                }
                else
                {
                    Operand isAGtIntMax = context.ICompareLess(srcA, Const(0));

                    res = context.ConditionalSelect(isAGtIntMax, srcA, res);
                }
            }
            else
            {
                // Ra and Rb have the same signedness, so doesn't matter which one we test.
                resSigned = (op.ASelect & VectorSelect.S8B0) != 0;

                if (op.Mn)
                {
                    res = resSigned
                        ? context.IMaximumS32(srcA, srcB)
                        : context.IMaximumU32(srcA, srcB);
                }
                else
                {
                    res = resSigned
                        ? context.IMinimumS32(srcA, srcB)
                        : context.IMinimumU32(srcA, srcB);
                }
            }

            if (op.Sat)
            {
                if (op.DFormat && !resSigned)
                {
                    res = context.IMinimumU32(res, Const(int.MaxValue));
                }
                else if (!op.DFormat && resSigned)
                {
                    res = context.IMaximumS32(res, Const(0));
                }
            }

            switch (op.VideoOp)
            {
            case VideoOp.Acc:
                res = context.IAdd(res, srcC);
                break;

            case VideoOp.Max:
                res = op.DFormat ? context.IMaximumS32(res, srcC) : context.IMaximumU32(res, srcC);
                break;

            case VideoOp.Min:
                res = op.DFormat ? context.IMinimumS32(res, srcC) : context.IMinimumU32(res, srcC);
                break;

            case VideoOp.Mrg16h:
                res = context.BitfieldInsert(srcC, res, Const(16), Const(16));
                break;

            case VideoOp.Mrg16l:
                res = context.BitfieldInsert(srcC, res, Const(0), Const(16));
                break;

            case VideoOp.Mrg8b0:
                res = context.BitfieldInsert(srcC, res, Const(0), Const(8));
                break;

            case VideoOp.Mrg8b2:
                res = context.BitfieldInsert(srcC, res, Const(16), Const(8));
                break;
            }

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