Пример #1
0
        public static void EmitVectorInsertF(AILEmitterCtx Context, int Reg, int Index, int Size)
        {
            ThrowIfInvalidF(Index, Size);

            Context.EmitLdvec(Reg);
            Context.EmitLdc_I4(Index);

            if (Size == 0)
            {
                AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInsertSingle));
            }
            else if (Size == 1)
            {
                AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInsertDouble));
            }
            else
            {
                throw new ArgumentOutOfRangeException(nameof(Size));
            }

            Context.EmitStvec(Reg);
        }
Пример #2
0
        public static void Fmin_V(AILEmitterCtx Context)
        {
            AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;

            int SizeF = Op.Size & 1;

            EmitVectorBinaryOpF(Context, () =>
            {
                if (SizeF == 0)
                {
                    AVectorHelper.EmitCall(Context, nameof(AVectorHelper.MinF));
                }
                else if (SizeF == 1)
                {
                    AVectorHelper.EmitCall(Context, nameof(AVectorHelper.Min));
                }
                else
                {
                    throw new InvalidOperationException();
                }
            });
        }
Пример #3
0
        public static void Frintx_V(AILEmitterCtx Context)
        {
            AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;

            EmitVectorUnaryOpF(Context, () =>
            {
                Context.EmitLdarg(ATranslatedSub.StateArgIdx);

                Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpcr));

                if (Op.Size == 0)
                {
                    AVectorHelper.EmitCall(Context, nameof(AVectorHelper.RoundF));
                }
                else if (Op.Size == 1)
                {
                    AVectorHelper.EmitCall(Context, nameof(AVectorHelper.Round));
                }
                else
                {
                    throw new InvalidOperationException();
                }
            });
        }
        public static void Cnt_V(AILEmitterCtx Context)
        {
            AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;

            int Elems = Op.RegisterSize == ARegisterSize.SIMD128 ? 16 : 8;

            for (int Index = 0; Index < Elems; Index++)
            {
                EmitVectorExtractZx(Context, Op.Rn, Index, 0);

                Context.Emit(OpCodes.Conv_U1);

                AVectorHelper.EmitCall(Context, nameof(AVectorHelper.CountSetBits8));

                Context.Emit(OpCodes.Conv_U8);

                EmitVectorInsert(Context, Op.Rd, Index, 0);
            }

            if (Op.RegisterSize == ARegisterSize.SIMD64)
            {
                EmitVectorZeroUpper(Context, Op.Rd);
            }
        }
Пример #5
0
        private static void EmitSseCall(AILEmitterCtx Context, string Name, Type Type)
        {
            AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;

            void Ldvec(int Reg)
            {
                Context.EmitLdvec(Reg);

                switch (Op.Size)
                {
                case 0: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToSByte)); break;

                case 1: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToInt16)); break;

                case 2: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToInt32)); break;

                case 3: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToInt64)); break;
                }
            }

            Ldvec(Op.Rn);

            Type BaseType = null;

            switch (Op.Size)
            {
            case 0: BaseType = typeof(Vector128 <sbyte>); break;

            case 1: BaseType = typeof(Vector128 <short>); break;

            case 2: BaseType = typeof(Vector128 <int>);   break;

            case 3: BaseType = typeof(Vector128 <long>);  break;
            }

            if (Op is AOpCodeSimdReg BinOp)
            {
                Ldvec(BinOp.Rm);

                Context.EmitCall(Type.GetMethod(Name, new Type[] { BaseType, BaseType }));
            }
            else
            {
                Context.EmitCall(Type.GetMethod(Name, new Type[] { BaseType }));
            }

            switch (Op.Size)
            {
            case 0: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSByteToSingle)); break;

            case 1: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInt16ToSingle)); break;

            case 2: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInt32ToSingle)); break;

            case 3: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInt64ToSingle)); break;
            }

            Context.EmitStvec(Op.Rd);

            if (Op.RegisterSize == ARegisterSize.SIMD64)
            {
                EmitVectorZeroUpper(Context, Op.Rd);
            }
        }
Пример #6
0
        public static void EmitSseOrSse2OpF(AILEmitterCtx Context, string Name, bool Scalar)
        {
            AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;

            int SizeF = Op.Size & 1;

            void Ldvec(int Reg)
            {
                Context.EmitLdvec(Reg);

                if (SizeF == 1)
                {
                    AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToDouble));
                }
            }

            Ldvec(Op.Rn);

            Type Type;
            Type BaseType;

            if (SizeF == 0)
            {
                Type     = typeof(Sse);
                BaseType = typeof(Vector128 <float>);
            }
            else /* if (SizeF == 1) */
            {
                Type     = typeof(Sse2);
                BaseType = typeof(Vector128 <double>);
            }

            if (Op is AOpCodeSimdReg BinOp)
            {
                Ldvec(BinOp.Rm);

                Context.EmitCall(Type.GetMethod(Name, new Type[] { BaseType, BaseType }));
            }
            else
            {
                Context.EmitCall(Type.GetMethod(Name, new Type[] { BaseType }));
            }

            if (SizeF == 1)
            {
                AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorDoubleToSingle));
            }

            Context.EmitStvec(Op.Rd);

            if (Scalar)
            {
                if (SizeF == 0)
                {
                    EmitVectorZero32_128(Context, Op.Rd);
                }
                else /* if (SizeF == 1) */
                {
                    EmitVectorZeroUpper(Context, Op.Rd);
                }
            }
            else if (Op.RegisterSize == ARegisterSize.SIMD64)
            {
                EmitVectorZeroUpper(Context, Op.Rd);
            }
        }
Пример #7
0
        public static void EmitStvecWithCastFromDouble(AILEmitterCtx Context, int Reg)
        {
            AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorDoubleToSingle));

            Context.EmitStvec(Reg);
        }
Пример #8
0
        public static void EmitLdvecWithCastToDouble(AILEmitterCtx Context, int Reg)
        {
            Context.EmitLdvec(Reg);

            AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToDouble));
        }
Пример #9
0
        public static void Xtn_V(AILEmitterCtx Context)
        {
            AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;

            int Elems = 8 >> Op.Size;

            int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;

            if (AOptimizations.UseSse41 && Op.Size < 2)
            {
                void EmitZeroVector()
                {
                    switch (Op.Size)
                    {
                    case 0: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInt16Zero)); break;

                    case 1: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInt32Zero)); break;
                    }
                }

                //For XTN, first operand is source, second operand is 0.
                //For XTN2, first operand is 0, second operand is source.
                if (Part != 0)
                {
                    EmitZeroVector();
                }

                EmitLdvecWithSignedCast(Context, Op.Rn, Op.Size + 1);

                //Set mask to discard the upper half of the wide elements.
                switch (Op.Size)
                {
                case 0: Context.EmitLdc_I4(0x00ff);     break;

                case 1: Context.EmitLdc_I4(0x0000ffff); break;
                }

                Type WideType = IntTypesPerSizeLog2[Op.Size + 1];

                Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), new Type[] { WideType }));

                WideType = VectorIntTypesPerSizeLog2[Op.Size + 1];

                Type[] WideTypes = new Type[] { WideType, WideType };

                Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), WideTypes));

                if (Part == 0)
                {
                    EmitZeroVector();
                }

                //Pack values with signed saturation, the signed saturation shouldn't
                //saturate anything since the upper bits were masked off.
                Type SseType = Op.Size == 0 ? typeof(Sse2) : typeof(Sse41);

                Context.EmitCall(SseType.GetMethod(nameof(Sse2.PackUnsignedSaturate), WideTypes));

                if (Part != 0)
                {
                    //For XTN2, we additionally need to discard the upper bits
                    //of the target register and OR the result with it.
                    EmitVectorZeroUpper(Context, Op.Rd);

                    EmitLdvecWithUnsignedCast(Context, Op.Rd, Op.Size);

                    Type NarrowType = VectorUIntTypesPerSizeLog2[Op.Size];

                    Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { NarrowType, NarrowType }));
                }

                EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size);
            }
            else
            {
                if (Part != 0)
                {
                    Context.EmitLdvec(Op.Rd);
                    Context.EmitStvectmp();
                }

                for (int Index = 0; Index < Elems; Index++)
                {
                    EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size + 1);

                    EmitVectorInsertTmp(Context, Part + Index, Op.Size);
                }

                Context.EmitLdvectmp();
                Context.EmitStvec(Op.Rd);

                if (Part == 0)
                {
                    EmitVectorZeroUpper(Context, Op.Rd);
                }
            }
        }