Esempio n. 1
0
        private static void EmitSse2OrAvxCmpOpF(ArmEmitterContext context, CmpCondition cond, bool scalar, bool absolute = false)
        {
            OpCodeSimd op = (OpCodeSimd)context.CurrOp;

            Operand n = GetVec(op.Rn);
            Operand m = op is OpCodeSimdReg binOp?GetVec(binOp.Rm) : context.VectorZero();

            int sizeF = op.Size & 1;

            if (sizeF == 0)
            {
                if (absolute)
                {
                    Operand mask = scalar ? X86GetScalar(context, int.MaxValue) : X86GetAllElements(context, int.MaxValue);

                    n = context.AddIntrinsic(Intrinsic.X86Andps, n, mask);
                    m = context.AddIntrinsic(Intrinsic.X86Andps, m, mask);
                }

                Intrinsic inst = scalar ? Intrinsic.X86Cmpss : Intrinsic.X86Cmpps;

                Operand res = context.AddIntrinsic(inst, n, m, Const((int)cond));

                if (scalar)
                {
                    res = context.VectorZeroUpper96(res);
                }
                else if (op.RegisterSize == RegisterSize.Simd64)
                {
                    res = context.VectorZeroUpper64(res);
                }

                context.Copy(GetVec(op.Rd), res);
            }
            else /* if (sizeF == 1) */
            {
                if (absolute)
                {
                    Operand mask = scalar ? X86GetScalar(context, long.MaxValue) : X86GetAllElements(context, long.MaxValue);

                    n = context.AddIntrinsic(Intrinsic.X86Andpd, n, mask);
                    m = context.AddIntrinsic(Intrinsic.X86Andpd, m, mask);
                }

                Intrinsic inst = scalar ? Intrinsic.X86Cmpsd : Intrinsic.X86Cmppd;

                Operand res = context.AddIntrinsic(inst, n, m, Const((int)cond));

                if (scalar)
                {
                    res = context.VectorZeroUpper64(res);
                }

                context.Copy(GetVec(op.Rd), res);
            }
        }
Esempio n. 2
0
        private static void EmitCmpSseOrSse2OpF(
            ArmEmitterContext context,
            CmpCondition cond,
            bool scalar,
            bool isLeOrLt = false)
        {
            OpCodeSimd op = (OpCodeSimd)context.CurrOp;

            Operand n = GetVec(op.Rn);
            Operand m = op is OpCodeSimdReg binOp?GetVec(binOp.Rm) : context.VectorZero();

            int sizeF = op.Size & 1;

            if (sizeF == 0)
            {
                Intrinsic inst = scalar ? Intrinsic.X86Cmpss : Intrinsic.X86Cmpps;

                Operand res = isLeOrLt
                    ? context.AddIntrinsic(inst, m, n, Const((int)cond))
                    : context.AddIntrinsic(inst, n, m, Const((int)cond));

                if (scalar)
                {
                    res = context.VectorZeroUpper96(res);
                }
                else if (op.RegisterSize == RegisterSize.Simd64)
                {
                    res = context.VectorZeroUpper64(res);
                }

                context.Copy(GetVec(op.Rd), res);
            }
            else /* if (sizeF == 1) */
            {
                Intrinsic inst = scalar ? Intrinsic.X86Cmpsd : Intrinsic.X86Cmppd;

                Operand res = isLeOrLt
                    ? context.AddIntrinsic(inst, m, n, Const((int)cond))
                    : context.AddIntrinsic(inst, n, m, Const((int)cond));

                if (scalar)
                {
                    res = context.VectorZeroUpper64(res);
                }

                context.Copy(GetVec(op.Rd), res);
            }
        }
Esempio n. 3
0
        private static void EmitSse2OrAvxCmpOpF32(ArmEmitterContext context, CmpCondition cond, bool zero)
        {
            OpCode32Simd op = (OpCode32Simd)context.CurrOp;

            int       sizeF = op.Size & 1;
            Intrinsic inst  = (sizeF == 0) ? Intrinsic.X86Cmpps : Intrinsic.X86Cmppd;

            if (zero)
            {
                EmitVectorUnaryOpSimd32(context, (m) =>
                {
                    return(context.AddIntrinsic(inst, m, context.VectorZero(), Const((int)cond)));
                });
            }
            else
            {
                EmitVectorBinaryOpSimd32(context, (n, m) =>
                {
                    return(context.AddIntrinsic(inst, n, m, Const((int)cond)));
                });
            }
        }
Esempio n. 4
0
        private static void EmitFcmpOrFcmpe(ArmEmitterContext context, bool signalNaNs)
        {
            OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;

            bool cmpWithZero = !(op is OpCodeSimdFcond) ? op.Bit3 : false;

            if (Optimizations.FastFP && (signalNaNs ? Optimizations.UseAvx : Optimizations.UseSse2))
            {
                Operand n = GetVec(op.Rn);
                Operand m = cmpWithZero ? context.VectorZero() : GetVec(op.Rm);

                CmpCondition cmpOrdered = signalNaNs ? CmpCondition.OrderedS : CmpCondition.OrderedQ;

                Operand lblNaN = Label();
                Operand lblEnd = Label();

                if (op.Size == 0)
                {
                    Operand ordMask = context.AddIntrinsic(Intrinsic.X86Cmpss, n, m, Const((int)cmpOrdered));

                    Operand isOrdered = context.AddIntrinsicInt(Intrinsic.X86Cvtsi2si, ordMask);

                    context.BranchIfFalse(lblNaN, isOrdered);

                    Operand nCopy = context.Copy(n);
                    Operand mCopy = cmpWithZero ? context.VectorZero() : context.Copy(m);

                    Operand cf = context.AddIntrinsicInt(Intrinsic.X86Comissge, nCopy, mCopy);
                    Operand zf = context.AddIntrinsicInt(Intrinsic.X86Comisseq, nCopy, mCopy);
                    Operand nf = context.AddIntrinsicInt(Intrinsic.X86Comisslt, nCopy, mCopy);

                    SetFlag(context, PState.VFlag, Const(0));
                    SetFlag(context, PState.CFlag, cf);
                    SetFlag(context, PState.ZFlag, zf);
                    SetFlag(context, PState.NFlag, nf);
                }
                else /* if (op.Size == 1) */
                {
                    Operand ordMask = context.AddIntrinsic(Intrinsic.X86Cmpsd, n, m, Const((int)cmpOrdered));

                    Operand isOrdered = context.AddIntrinsicLong(Intrinsic.X86Cvtsi2si, ordMask);

                    context.BranchIfFalse(lblNaN, isOrdered);

                    Operand nCopy = context.Copy(n);
                    Operand mCopy = cmpWithZero ? context.VectorZero() : context.Copy(m);

                    Operand cf = context.AddIntrinsicInt(Intrinsic.X86Comisdge, nCopy, mCopy);
                    Operand zf = context.AddIntrinsicInt(Intrinsic.X86Comisdeq, nCopy, mCopy);
                    Operand nf = context.AddIntrinsicInt(Intrinsic.X86Comisdlt, nCopy, mCopy);

                    SetFlag(context, PState.VFlag, Const(0));
                    SetFlag(context, PState.CFlag, cf);
                    SetFlag(context, PState.ZFlag, zf);
                    SetFlag(context, PState.NFlag, nf);
                }

                context.Branch(lblEnd);

                context.MarkLabel(lblNaN);

                SetFlag(context, PState.VFlag, Const(1));
                SetFlag(context, PState.CFlag, Const(1));
                SetFlag(context, PState.ZFlag, Const(0));
                SetFlag(context, PState.NFlag, Const(0));

                context.MarkLabel(lblEnd);
            }
            else
            {
                OperandType type = op.Size != 0 ? OperandType.FP64 : OperandType.FP32;

                Operand ne = context.VectorExtract(type, GetVec(op.Rn), 0);
                Operand me;

                if (cmpWithZero)
                {
                    me = op.Size == 0 ? ConstF(0f) : ConstF(0d);
                }
                else
                {
                    me = context.VectorExtract(type, GetVec(op.Rm), 0);
                }

                Operand nzcv = EmitSoftFloatCall(context, nameof(SoftFloat32.FPCompare), ne, me, Const(signalNaNs));

                EmitSetNzcv(context, nzcv);
            }
        }
Esempio n. 5
0
        private static void EmitVcmpOrVcmpe(ArmEmitterContext context, bool signalNaNs)
        {
            OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;

            bool cmpWithZero = (op.Opc & 2) != 0;
            int  sizeF       = op.Size & 1;

            if (Optimizations.FastFP && (signalNaNs ? Optimizations.UseAvx : Optimizations.UseSse2))
            {
                CmpCondition cmpOrdered = signalNaNs ? CmpCondition.OrderedS : CmpCondition.OrderedQ;

                bool    doubleSize = sizeF != 0;
                int     shift      = doubleSize ? 1 : 2;
                Operand m          = GetVecA32(op.Vm >> shift);
                Operand n          = GetVecA32(op.Vd >> shift);

                n = EmitSwapScalar(context, n, op.Vd, doubleSize);
                m = cmpWithZero ? context.VectorZero() : EmitSwapScalar(context, m, op.Vm, doubleSize);

                Operand lblNaN = Label();
                Operand lblEnd = Label();

                if (!doubleSize)
                {
                    Operand ordMask = context.AddIntrinsic(Intrinsic.X86Cmpss, n, m, Const((int)cmpOrdered));

                    Operand isOrdered = context.AddIntrinsicInt(Intrinsic.X86Cvtsi2si, ordMask);

                    context.BranchIfFalse(lblNaN, isOrdered);

                    Operand cf = context.AddIntrinsicInt(Intrinsic.X86Comissge, n, m);
                    Operand zf = context.AddIntrinsicInt(Intrinsic.X86Comisseq, n, m);
                    Operand nf = context.AddIntrinsicInt(Intrinsic.X86Comisslt, n, m);

                    SetFpFlag(context, FPState.VFlag, Const(0));
                    SetFpFlag(context, FPState.CFlag, cf);
                    SetFpFlag(context, FPState.ZFlag, zf);
                    SetFpFlag(context, FPState.NFlag, nf);
                }
                else
                {
                    Operand ordMask = context.AddIntrinsic(Intrinsic.X86Cmpsd, n, m, Const((int)cmpOrdered));

                    Operand isOrdered = context.AddIntrinsicLong(Intrinsic.X86Cvtsi2si, ordMask);

                    context.BranchIfFalse(lblNaN, isOrdered);

                    Operand cf = context.AddIntrinsicInt(Intrinsic.X86Comisdge, n, m);
                    Operand zf = context.AddIntrinsicInt(Intrinsic.X86Comisdeq, n, m);
                    Operand nf = context.AddIntrinsicInt(Intrinsic.X86Comisdlt, n, m);

                    SetFpFlag(context, FPState.VFlag, Const(0));
                    SetFpFlag(context, FPState.CFlag, cf);
                    SetFpFlag(context, FPState.ZFlag, zf);
                    SetFpFlag(context, FPState.NFlag, nf);
                }

                context.Branch(lblEnd);

                context.MarkLabel(lblNaN);

                SetFpFlag(context, FPState.VFlag, Const(1));
                SetFpFlag(context, FPState.CFlag, Const(1));
                SetFpFlag(context, FPState.ZFlag, Const(0));
                SetFpFlag(context, FPState.NFlag, Const(0));

                context.MarkLabel(lblEnd);
            }
            else
            {
                OperandType type = sizeF != 0 ? OperandType.FP64 : OperandType.FP32;

                Operand ne = ExtractScalar(context, type, op.Vd);
                Operand me;

                if (cmpWithZero)
                {
                    me = sizeF == 0 ? ConstF(0f) : ConstF(0d);
                }
                else
                {
                    me = ExtractScalar(context, type, op.Vm);
                }

                MethodInfo info = sizeF != 0
                    ? typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare))
                    : typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare));

                Operand nzcv = context.Call(info, ne, me, Const(signalNaNs));

                EmitSetFpscrNzcv(context, nzcv);
            }
        }