Exemple #1
0
        private static void EmitCsel(AILEmitterCtx Context, CselOperation CselOp)
        {
            AOpCodeCsel Op = (AOpCodeCsel)Context.CurrOp;

            AILLabel LblTrue = new AILLabel();
            AILLabel LblEnd  = new AILLabel();

            Context.EmitCondBranch(LblTrue, Op.Cond);
            Context.EmitLdintzr(Op.Rm);

            if (CselOp == CselOperation.Increment)
            {
                Context.EmitLdc_I(1);

                Context.Emit(OpCodes.Add);
            }
            else if (CselOp == CselOperation.Invert)
            {
                Context.Emit(OpCodes.Not);
            }
            else if (CselOp == CselOperation.Negate)
            {
                Context.Emit(OpCodes.Neg);
            }

            Context.Emit(OpCodes.Br_S, LblEnd);

            Context.MarkLabel(LblTrue);

            Context.EmitLdintzr(Op.Rn);

            Context.MarkLabel(LblEnd);

            Context.EmitStintzr(Op.Rd);
        }
        public static void Fccmp_S(AILEmitterCtx Context)
        {
            AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp;

            AILLabel LblTrue = new AILLabel();
            AILLabel LblEnd  = new AILLabel();

            Context.EmitCondBranch(LblTrue, Op.Cond);

            //TODO: Share this logic with Ccmp.
            Context.EmitLdc_I4((Op.NZCV >> 0) & 1);

            Context.EmitStflg((int)APState.VBit);

            Context.EmitLdc_I4((Op.NZCV >> 1) & 1);

            Context.EmitStflg((int)APState.CBit);

            Context.EmitLdc_I4((Op.NZCV >> 2) & 1);

            Context.EmitStflg((int)APState.ZBit);

            Context.EmitLdc_I4((Op.NZCV >> 3) & 1);

            Context.EmitStflg((int)APState.NBit);

            Context.Emit(OpCodes.Br_S, LblEnd);

            Context.MarkLabel(LblTrue);

            Fcmp_S(Context);

            Context.MarkLabel(LblEnd);
        }
Exemple #3
0
        private static void EmitCcmp(AILEmitterCtx Context, CcmpOp CmpOp)
        {
            AOpCodeCcmp Op = (AOpCodeCcmp)Context.CurrOp;

            AILLabel LblTrue = new AILLabel();
            AILLabel LblEnd  = new AILLabel();

            Context.EmitCondBranch(LblTrue, Op.Cond);

            Context.EmitLdc_I4((Op.NZCV >> 0) & 1);

            Context.EmitStflg((int)APState.VBit);

            Context.EmitLdc_I4((Op.NZCV >> 1) & 1);

            Context.EmitStflg((int)APState.CBit);

            Context.EmitLdc_I4((Op.NZCV >> 2) & 1);

            Context.EmitStflg((int)APState.ZBit);

            Context.EmitLdc_I4((Op.NZCV >> 3) & 1);

            Context.EmitStflg((int)APState.NBit);

            Context.Emit(OpCodes.Br_S, LblEnd);

            Context.MarkLabel(LblTrue);

            EmitDataLoadOpers(Context);

            if (CmpOp == CcmpOp.Cmp)
            {
                Context.Emit(OpCodes.Sub);

                Context.EmitZNFlagCheck();

                EmitSubsCCheck(Context);
                EmitSubsVCheck(Context);
            }
            else if (CmpOp == CcmpOp.Cmn)
            {
                Context.Emit(OpCodes.Add);

                Context.EmitZNFlagCheck();

                EmitAddsCCheck(Context);
                EmitAddsVCheck(Context);
            }
            else
            {
                throw new ArgumentException(nameof(CmpOp));
            }

            Context.Emit(OpCodes.Pop);

            Context.MarkLabel(LblEnd);
        }
        private static void EmitStore(AILEmitterCtx Context, AccessType AccType, bool Pair)
        {
            AOpCodeMemEx Op = (AOpCodeMemEx)Context.CurrOp;

            bool Ordered   = (AccType & AccessType.Ordered) != 0;
            bool Exclusive = (AccType & AccessType.Exclusive) != 0;

            if (Ordered)
            {
                EmitBarrier(Context);
            }

            AILLabel LblEx  = new AILLabel();
            AILLabel LblEnd = new AILLabel();

            if (Exclusive)
            {
                EmitMemoryCall(Context, nameof(AMemory.TestExclusive), Op.Rn);

                Context.Emit(OpCodes.Brtrue_S, LblEx);

                Context.EmitLdc_I8(1);
                Context.EmitStintzr(Op.Rs);

                Context.Emit(OpCodes.Br_S, LblEnd);
            }

            Context.MarkLabel(LblEx);

            Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
            Context.EmitLdint(Op.Rn);
            Context.EmitLdintzr(Op.Rt);

            EmitWriteCall(Context, Op.Size);

            if (Pair)
            {
                Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
                Context.EmitLdint(Op.Rn);
                Context.EmitLdc_I8(1 << Op.Size);

                Context.Emit(OpCodes.Add);

                Context.EmitLdintzr(Op.Rt2);

                EmitWriteCall(Context, Op.Size);
            }

            if (Exclusive)
            {
                Context.EmitLdc_I8(0);
                Context.EmitStintzr(Op.Rs);

                EmitMemoryCall(Context, nameof(AMemory.ClearExclusiveForStore));
            }

            Context.MarkLabel(LblEnd);
        }
        private static void EmitFcmp(AILEmitterCtx Context, OpCode ILOp, int Index, bool Scalar)
        {
            AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;

            int SizeF = Op.Size & 1;

            ulong SzMask = ulong.MaxValue >> (64 - (32 << SizeF));

            EmitVectorExtractF(Context, Op.Rn, Index, SizeF);

            if (Op is AOpCodeSimdReg BinOp)
            {
                EmitVectorExtractF(Context, BinOp.Rm, Index, SizeF);
            }
            else if (SizeF == 0)
            {
                Context.EmitLdc_R4(0);
            }
            else /* if (SizeF == 1) */
            {
                Context.EmitLdc_R8(0);
            }

            AILLabel LblTrue = new AILLabel();
            AILLabel LblEnd  = new AILLabel();

            Context.Emit(ILOp, LblTrue);

            if (Scalar)
            {
                EmitVectorZeroAll(Context, Op.Rd);
            }
            else
            {
                EmitVectorInsert(Context, Op.Rd, Index, SizeF + 2, 0);
            }

            Context.Emit(OpCodes.Br_S, LblEnd);

            Context.MarkLabel(LblTrue);

            if (Scalar)
            {
                EmitVectorInsert(Context, Op.Rd, Index, 3, (long)SzMask);

                EmitVectorZeroUpper(Context, Op.Rd);
            }
            else
            {
                EmitVectorInsert(Context, Op.Rd, Index, SizeF + 2, (long)SzMask);
            }

            Context.MarkLabel(LblEnd);
        }
Exemple #6
0
        private static void EmitVectorShl(AILEmitterCtx Context, bool Signed)
        {
            //This instruction shifts the value on vector A by the number of bits
            //specified on the signed, lower 8 bits of vector B. If the shift value
            //is greater or equal to the data size of each lane, then the result is zero.
            //Additionally, negative shifts produces right shifts by the negated shift value.
            AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;

            int MaxShift = 8 << Op.Size;

            EmitVectorBinaryZx(Context, () =>
            {
                AILLabel LblShl  = new AILLabel();
                AILLabel LblZero = new AILLabel();
                AILLabel LblEnd  = new AILLabel();

                void EmitShift(OpCode ILOp)
                {
                    Context.Emit(OpCodes.Dup);

                    Context.EmitLdc_I4(MaxShift);

                    Context.Emit(OpCodes.Bge_S, LblZero);
                    Context.Emit(ILOp);
                    Context.Emit(OpCodes.Br_S, LblEnd);
                }

                Context.Emit(OpCodes.Conv_I1);
                Context.Emit(OpCodes.Dup);

                Context.EmitLdc_I4(0);

                Context.Emit(OpCodes.Bge_S, LblShl);
                Context.Emit(OpCodes.Neg);

                EmitShift(Signed
                    ? OpCodes.Shr
                    : OpCodes.Shr_Un);

                Context.MarkLabel(LblShl);

                EmitShift(OpCodes.Shl);

                Context.MarkLabel(LblZero);

                Context.Emit(OpCodes.Pop);
                Context.Emit(OpCodes.Pop);

                Context.EmitLdc_I8(0);

                Context.MarkLabel(LblEnd);
            });
        }
Exemple #7
0
        private static void EmitBranch(AILEmitterCtx Context, OpCode ILOp)
        {
            AOpCodeBImm Op = (AOpCodeBImm)Context.CurrOp;

            if (Context.CurrBlock.Next != null &&
                Context.CurrBlock.Branch != null)
            {
                Context.Emit(ILOp, Context.GetLabel(Op.Imm));
            }
            else
            {
                Context.EmitStoreState();

                AILLabel LblTaken = new AILLabel();

                Context.Emit(ILOp, LblTaken);

                Context.EmitLdc_I8(Op.Position + 4);

                Context.Emit(OpCodes.Ret);

                Context.MarkLabel(LblTaken);

                Context.EmitLdc_I8(Op.Imm);

                Context.Emit(OpCodes.Ret);
            }
        }
Exemple #8
0
        private static void EmitDoublingMultiplyHighHalf(AILEmitterCtx Context, bool Round)
        {
            AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;

            int ESize = 8 << Op.Size;

            Context.Emit(OpCodes.Mul);

            if (!Round)
            {
                Context.EmitAsr(ESize - 1);
            }
            else
            {
                long RoundConst = 1L << (ESize - 1);

                AILLabel LblTrue = new AILLabel();

                Context.EmitLsl(1);

                Context.EmitLdc_I8(RoundConst);

                Context.Emit(OpCodes.Add);

                Context.EmitAsr(ESize);

                Context.Emit(OpCodes.Dup);
                Context.EmitLdc_I8((long)int.MinValue);
                Context.Emit(OpCodes.Bne_Un_S, LblTrue);

                Context.Emit(OpCodes.Neg);

                Context.MarkLabel(LblTrue);
            }
        }
        public static void Fccmp_S(AILEmitterCtx Context)
        {
            AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp;

            AILLabel LblTrue = new AILLabel();
            AILLabel LblEnd  = new AILLabel();

            Context.EmitCondBranch(LblTrue, Op.Cond);

            EmitSetNZCV(Context, Op.NZCV);

            Context.Emit(OpCodes.Br, LblEnd);

            Context.MarkLabel(LblTrue);

            Fcmp_S(Context);

            Context.MarkLabel(LblEnd);
        }
        private static void EmitCmp(AILEmitterCtx Context, OpCode ILOp, bool Scalar)
        {
            AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;

            int Bytes = Op.GetBitsCount() >> 3;
            int Elems = !Scalar ? Bytes >> Op.Size : 1;

            ulong SzMask = ulong.MaxValue >> (64 - (8 << Op.Size));

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

                if (Op is AOpCodeSimdReg BinOp)
                {
                    EmitVectorExtractSx(Context, BinOp.Rm, Index, Op.Size);
                }
                else
                {
                    Context.EmitLdc_I8(0);
                }

                AILLabel LblTrue = new AILLabel();
                AILLabel LblEnd  = new AILLabel();

                Context.Emit(ILOp, LblTrue);

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

                Context.Emit(OpCodes.Br_S, LblEnd);

                Context.MarkLabel(LblTrue);

                EmitVectorInsert(Context, Op.Rd, Index, Op.Size, (long)SzMask);

                Context.MarkLabel(LblEnd);
            }

            if ((Op.RegisterSize == ARegisterSize.SIMD64) || Scalar)
            {
                EmitVectorZeroUpper(Context, Op.Rd);
            }
        }
        public static void Fcsel_S(AILEmitterCtx Context)
        {
            AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp;

            AILLabel LblTrue = new AILLabel();
            AILLabel LblEnd  = new AILLabel();

            Context.EmitCondBranch(LblTrue, Op.Cond);
            Context.EmitLdvecsf(Op.Rm);
            Context.EmitStvecsf(Op.Rd);

            Context.Emit(OpCodes.Br_S, LblEnd);

            Context.MarkLabel(LblTrue);

            Context.EmitLdvecsf(Op.Rn);
            Context.EmitStvecsf(Op.Rd);

            Context.MarkLabel(LblEnd);
        }
Exemple #12
0
        public static void Fcsel_S(AILEmitterCtx Context)
        {
            AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp;

            AILLabel LblTrue = new AILLabel();
            AILLabel LblEnd  = new AILLabel();

            Context.EmitCondBranch(LblTrue, Op.Cond);

            EmitVectorExtractF(Context, Op.Rm, 0, Op.Size);

            Context.Emit(OpCodes.Br_S, LblEnd);

            Context.MarkLabel(LblTrue);

            EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);

            Context.MarkLabel(LblEnd);

            EmitScalarSetF(Context, Op.Rd, Op.Size);
        }
Exemple #13
0
        private static void EmitAbs(AILEmitterCtx Context)
        {
            AILLabel LblTrue = new AILLabel();

            Context.Emit(OpCodes.Dup);
            Context.Emit(OpCodes.Ldc_I4_0);
            Context.Emit(OpCodes.Bge_S, LblTrue);

            Context.Emit(OpCodes.Neg);

            Context.MarkLabel(LblTrue);
        }
Exemple #14
0
        public static void Cmtst_V(AILEmitterCtx Context)
        {
            AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;

            int Bytes = Context.CurrOp.GetBitsCount() >> 3;

            ulong SzMask = ulong.MaxValue >> (64 - (8 << Op.Size));

            for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
            {
                EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size);
                EmitVectorExtractZx(Context, Op.Rm, Index, Op.Size);

                AILLabel LblTrue = new AILLabel();
                AILLabel LblEnd  = new AILLabel();

                Context.Emit(OpCodes.And);

                Context.EmitLdc_I4(0);

                Context.Emit(OpCodes.Bne_Un_S, LblTrue);

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

                Context.Emit(OpCodes.Br_S, LblEnd);

                Context.MarkLabel(LblTrue);

                EmitVectorInsert(Context, Op.Rd, Index, Op.Size, (long)SzMask);

                Context.MarkLabel(LblEnd);
            }

            if (Op.RegisterSize == ARegisterSize.SIMD64)
            {
                EmitVectorZeroUpper(Context, Op.Rd);
            }
        }
Exemple #15
0
        private static void EmitDiv(AILEmitterCtx Context, OpCode ILOp)
        {
            //If Rm == 0, Rd = 0 (division by zero).
            Context.EmitLdc_I(0);

            EmitDataLoadRm(Context);

            Context.EmitLdc_I(0);

            AILLabel BadDiv = new AILLabel();

            Context.Emit(OpCodes.Beq_S, BadDiv);
            Context.Emit(OpCodes.Pop);

            if (ILOp == OpCodes.Div)
            {
                //If Rn == INT_MIN && Rm == -1, Rd = INT_MIN (overflow).
                long IntMin = 1L << (Context.CurrOp.GetBitsCount() - 1);

                Context.EmitLdc_I(IntMin);

                EmitDataLoadRn(Context);

                Context.EmitLdc_I(IntMin);

                Context.Emit(OpCodes.Ceq);

                EmitDataLoadRm(Context);

                Context.EmitLdc_I(-1);

                Context.Emit(OpCodes.Ceq);
                Context.Emit(OpCodes.And);
                Context.Emit(OpCodes.Brtrue_S, BadDiv);
                Context.Emit(OpCodes.Pop);
            }

            EmitDataLoadRn(Context);
            EmitDataLoadRm(Context);

            Context.Emit(ILOp);

            Context.MarkLabel(BadDiv);

            EmitDataStore(Context);
        }
Exemple #16
0
        public static void Bl(AILEmitterCtx Context)
        {
            AOpCodeBImmAl Op = (AOpCodeBImmAl)Context.CurrOp;

            if (AOptimizations.GenerateCallStack)
            {
                Context.EmitLdarg(ATranslatedSub.StateArgIdx);
                Context.EmitLdc_I8(Op.Imm);

                Context.EmitPrivateCall(typeof(AThreadState), nameof(AThreadState.EnterMethod));
            }

            Context.EmitLdc_I(Op.Position + 4);
            Context.EmitStint(AThreadState.LRIndex);
            Context.EmitStoreState();

            if (Context.TryOptEmitSubroutineCall())
            {
                //Note: the return value of the called method will be placed
                //at the Stack, the return value is always a Int64 with the
                //return address of the function. We check if the address is
                //correct, if it isn't we keep returning until we reach the dispatcher.
                Context.Emit(OpCodes.Dup);

                Context.EmitLdc_I8(Op.Position + 4);

                AILLabel LblContinue = new AILLabel();

                Context.Emit(OpCodes.Beq_S, LblContinue);
                Context.Emit(OpCodes.Ret);

                Context.MarkLabel(LblContinue);

                Context.Emit(OpCodes.Pop);

                Context.EmitLoadState(Context.CurrBlock.Next);
            }
            else
            {
                Context.EmitLdc_I8(Op.Imm);

                Context.Emit(OpCodes.Ret);
            }
        }
        private static void EmitExceptionCall(AILEmitterCtx Context, string MthdName)
        {
            AOpCodeException Op = (AOpCodeException)Context.CurrOp;

            Context.EmitStoreState();

            Context.EmitLdarg(ATranslatedSub.StateArgIdx);

            Context.EmitLdc_I4(Op.Id);

            MethodInfo MthdInfo = typeof(AThreadState).GetMethod(MthdName, Binding);

            Context.EmitCall(MthdInfo);

            //Check if the thread should still be running, if it isn't then we return 0
            //to force a return to the dispatcher and then exit the thread.
            Context.EmitLdarg(ATranslatedSub.StateArgIdx);

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

            AILLabel LblEnd = new AILLabel();

            Context.Emit(OpCodes.Brtrue_S, LblEnd);

            Context.EmitLdc_I8(0);

            Context.Emit(OpCodes.Ret);

            Context.MarkLabel(LblEnd);

            if (Context.CurrBlock.Next != null)
            {
                Context.EmitLoadState(Context.CurrBlock.Next);
            }
            else
            {
                Context.EmitLdc_I8(Op.Position + 4);

                Context.Emit(OpCodes.Ret);
            }
        }
Exemple #18
0
        public static void Bl(AILEmitterCtx Context)
        {
            AOpCodeBImmAl Op = (AOpCodeBImmAl)Context.CurrOp;

            Context.EmitLdc_I(Op.Position + 4);
            Context.EmitStint(ARegisters.LRIndex);
            Context.EmitStoreState();

            if (Context.TryOptEmitSubroutineCall())
            {
                //Note: the return value of the called method will be placed
                //at the Stack, the return value is always a Int64 with the
                //return address of the function. We check if the address is
                //correct, if it isn't we keep returning until we reach the dispatcher.
                Context.Emit(OpCodes.Dup);

                Context.EmitLdc_I8(Op.Position + 4);

                AILLabel LblContinue = new AILLabel();

                Context.Emit(OpCodes.Beq_S, LblContinue);
                Context.Emit(OpCodes.Ret);

                Context.MarkLabel(LblContinue);

                Context.Emit(OpCodes.Pop);

                if (Context.CurrBlock.Next != null)
                {
                    Context.EmitLoadState(Context.CurrBlock.Next);
                }
            }
            else
            {
                Context.EmitLdc_I8(Op.Imm);

                Context.Emit(OpCodes.Ret);
            }
        }
Exemple #19
0
        // TSrc (8bit, 16bit, 32bit, 64bit) == TDst (8bit, 16bit, 32bit, 64bit); signed.
        public static void EmitUnarySignedSatQAbsOrNeg(AILEmitterCtx Context, int Size)
        {
            int ESize = 8 << Size;

            long TMaxValue = (1L << (ESize - 1)) - 1L;
            long TMinValue = -(1L << (ESize - 1));

            AILLabel LblFalse = new AILLabel();

            Context.Emit(OpCodes.Dup);
            Context.Emit(OpCodes.Neg);
            Context.EmitLdc_I8(TMinValue);
            Context.Emit(OpCodes.Ceq);
            Context.Emit(OpCodes.Brfalse_S, LblFalse);

            Context.Emit(OpCodes.Pop);

            EmitSetFpsrQCFlag(Context);

            Context.EmitLdc_I8(TMaxValue);

            Context.MarkLabel(LblFalse);
        }
        public static void Fcmp_S(AILEmitterCtx Context)
        {
            AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;

            bool CmpWithZero = !(Op is AOpCodeSimdFcond) ? Op.Bit3 : false;

            //todo
            //Context.TryMarkCondWithoutCmp();

            void EmitLoadOpers()
            {
                Context.EmitLdvecsf(Op.Rn);

                if (CmpWithZero)
                {
                    EmitLdcImmF(Context, 0, Op.Size);
                }
                else
                {
                    Context.EmitLdvecsf(Op.Rm);
                }
            }

            //Z = Rn == Rm
            EmitLoadOpers();

            Context.Emit(OpCodes.Ceq);
            Context.Emit(OpCodes.Dup);

            Context.EmitStflg((int)APState.ZBit);

            //C = Rn >= Rm
            EmitLoadOpers();

            Context.Emit(OpCodes.Cgt);
            Context.Emit(OpCodes.Or);

            Context.EmitStflg((int)APState.CBit);

            //N = Rn < Rm
            EmitLoadOpers();

            Context.Emit(OpCodes.Clt);

            Context.EmitStflg((int)APState.NBit);

            //Handle NaN case. If any number is NaN, then NZCV = 0011.
            AILLabel LblNotNaN = new AILLabel();

            if (CmpWithZero)
            {
                EmitNaNCheck(Context, Op.Rn);
            }
            else
            {
                EmitNaNCheck(Context, Op.Rn);
                EmitNaNCheck(Context, Op.Rm);

                Context.Emit(OpCodes.Or);
            }

            Context.Emit(OpCodes.Brfalse_S, LblNotNaN);

            Context.EmitLdc_I4(1);
            Context.EmitLdc_I4(1);

            Context.EmitStflg((int)APState.CBit);
            Context.EmitStflg((int)APState.VBit);

            Context.MarkLabel(LblNotNaN);
        }
Exemple #21
0
        public static void EmitSaturatingNarrowOp(
            AILEmitterCtx Context,
            Action Emit,
            bool SignedSrc,
            bool SignedDst,
            bool Scalar)
        {
            AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;

            int Elems = !Scalar ? 8 >> Op.Size : 1;

            int ESize = 8 << Op.Size;

            int Part = !Scalar && (Op.RegisterSize == ARegisterSize.SIMD128) ? Elems : 0;

            long TMaxValue = SignedDst ? (1 << (ESize - 1)) - 1 : (1L << ESize) - 1L;
            long TMinValue = SignedDst ? -((1 << (ESize - 1))) : 0;

            Context.EmitLdc_I8(0L);
            Context.EmitSttmp();

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

            for (int Index = 0; Index < Elems; Index++)
            {
                AILLabel LblLe    = new AILLabel();
                AILLabel LblGeEnd = new AILLabel();

                EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, SignedSrc);

                Emit();

                Context.Emit(OpCodes.Dup);

                Context.EmitLdc_I8(TMaxValue);

                Context.Emit(SignedSrc ? OpCodes.Ble_S : OpCodes.Ble_Un_S, LblLe);

                Context.Emit(OpCodes.Pop);

                Context.EmitLdc_I8(TMaxValue);
                Context.EmitLdc_I8(0x8000000L);
                Context.EmitSttmp();

                Context.Emit(OpCodes.Br_S, LblGeEnd);

                Context.MarkLabel(LblLe);

                Context.Emit(OpCodes.Dup);

                Context.EmitLdc_I8(TMinValue);

                Context.Emit(SignedSrc ? OpCodes.Bge_S : OpCodes.Bge_Un_S, LblGeEnd);

                Context.Emit(OpCodes.Pop);

                Context.EmitLdc_I8(TMinValue);
                Context.EmitLdc_I8(0x8000000L);
                Context.EmitSttmp();

                Context.MarkLabel(LblGeEnd);

                if (Scalar)
                {
                    EmitVectorZeroLower(Context, Op.Rd);
                }

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

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

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

            Context.EmitLdarg(ATranslatedSub.StateArgIdx);
            Context.EmitLdarg(ATranslatedSub.StateArgIdx);
            Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpsr));
            Context.EmitLdtmp();
            Context.Emit(OpCodes.Conv_I4);
            Context.Emit(OpCodes.Or);
            Context.EmitCallPropSet(typeof(AThreadState), nameof(AThreadState.Fpsr));
        }
        public static void Fcmp_S(AILEmitterCtx Context)
        {
            AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;

            bool CmpWithZero = !(Op is AOpCodeSimdFcond) ? Op.Bit3 : false;

            //Handle NaN case.
            //If any number is NaN, then NZCV = 0011.
            if (CmpWithZero)
            {
                EmitNaNCheck(Context, Op.Rn);
            }
            else
            {
                EmitNaNCheck(Context, Op.Rn);
                EmitNaNCheck(Context, Op.Rm);

                Context.Emit(OpCodes.Or);
            }

            AILLabel LblNaN = new AILLabel();
            AILLabel LblEnd = new AILLabel();

            Context.Emit(OpCodes.Brtrue_S, LblNaN);

            void EmitLoadOpers()
            {
                EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);

                if (CmpWithZero)
                {
                    if (Op.Size == 0)
                    {
                        Context.EmitLdc_R4(0);
                    }
                    else /* if (SizeF == 1) */
                    {
                        Context.EmitLdc_R8(0);
                    }
                }
                else
                {
                    EmitVectorExtractF(Context, Op.Rm, 0, Op.Size);
                }
            }

            //Z = Rn == Rm
            EmitLoadOpers();

            Context.Emit(OpCodes.Ceq);
            Context.Emit(OpCodes.Dup);

            Context.EmitStflg((int)APState.ZBit);

            //C = Rn >= Rm
            EmitLoadOpers();

            Context.Emit(OpCodes.Cgt);
            Context.Emit(OpCodes.Or);

            Context.EmitStflg((int)APState.CBit);

            //N = Rn < Rm
            EmitLoadOpers();

            Context.Emit(OpCodes.Clt);

            Context.EmitStflg((int)APState.NBit);

            //V = 0
            Context.EmitLdc_I4(0);

            Context.EmitStflg((int)APState.VBit);

            Context.Emit(OpCodes.Br_S, LblEnd);

            Context.MarkLabel(LblNaN);

            EmitSetNZCV(Context, 0b0011);

            Context.MarkLabel(LblEnd);
        }
        private static void EmitQxtn(AILEmitterCtx Context, bool Signed, bool Scalar)
        {
            AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;

            int Elems = (!Scalar ? 8 >> Op.Size : 1);
            int ESize = 8 << Op.Size;

            int TMaxValue = (Signed ? (1 << (ESize - 1)) - 1 : (int)((1L << ESize) - 1L));
            int TMinValue = (Signed ? -((1 << (ESize - 1))) : 0);

            int Part = (!Scalar & (Op.RegisterSize == ARegisterSize.SIMD128) ? Elems : 0);

            Context.EmitLdc_I8(0L);
            Context.EmitSttmp();

            for (int Index = 0; Index < Elems; Index++)
            {
                AILLabel LblLe    = new AILLabel();
                AILLabel LblGeEnd = new AILLabel();

                EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, Signed);

                Context.Emit(OpCodes.Dup);

                Context.EmitLdc_I4(TMaxValue);
                Context.Emit(OpCodes.Conv_U8);

                Context.Emit(Signed ? OpCodes.Ble_S : OpCodes.Ble_Un_S, LblLe);

                Context.Emit(OpCodes.Pop);

                Context.EmitLdc_I4(TMaxValue);

                Context.EmitLdc_I8(0x8000000L);
                Context.EmitSttmp();

                Context.Emit(OpCodes.Br_S, LblGeEnd);

                Context.MarkLabel(LblLe);

                Context.Emit(OpCodes.Dup);

                Context.EmitLdc_I4(TMinValue);
                Context.Emit(OpCodes.Conv_I8);

                Context.Emit(Signed ? OpCodes.Bge_S : OpCodes.Bge_Un_S, LblGeEnd);

                Context.Emit(OpCodes.Pop);

                Context.EmitLdc_I4(TMinValue);

                Context.EmitLdc_I8(0x8000000L);
                Context.EmitSttmp();

                Context.MarkLabel(LblGeEnd);

                if (Scalar)
                {
                    EmitVectorZeroLower(Context, Op.Rd);
                }

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

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

            Context.EmitLdarg(ATranslatedSub.StateArgIdx);
            Context.EmitLdarg(ATranslatedSub.StateArgIdx);
            Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpsr));
            Context.EmitLdtmp();
            Context.Emit(OpCodes.Conv_I4);
            Context.Emit(OpCodes.Or);
            Context.EmitCallPropSet(typeof(AThreadState), nameof(AThreadState.Fpsr));
        }