예제 #1
0
        public static void EmitSetNzcv(ILEmitterCtx context)
        {
            context.Emit(OpCodes.Dup);
            context.Emit(OpCodes.Ldc_I4_1);
            context.Emit(OpCodes.And);
            context.EmitStflg((int)PState.VBit);

            context.Emit(OpCodes.Ldc_I4_1);
            context.Emit(OpCodes.Shr);
            context.Emit(OpCodes.Dup);
            context.Emit(OpCodes.Ldc_I4_1);
            context.Emit(OpCodes.And);
            context.EmitStflg((int)PState.CBit);

            context.Emit(OpCodes.Ldc_I4_1);
            context.Emit(OpCodes.Shr);
            context.Emit(OpCodes.Dup);
            context.Emit(OpCodes.Ldc_I4_1);
            context.Emit(OpCodes.And);
            context.EmitStflg((int)PState.ZBit);

            context.Emit(OpCodes.Ldc_I4_1);
            context.Emit(OpCodes.Shr);
            context.Emit(OpCodes.Ldc_I4_1);
            context.Emit(OpCodes.And);
            context.EmitStflg((int)PState.NBit);
        }
예제 #2
0
        private static void EmitAsrC(ILEmitterCtx context, bool setCarry, int shift)
        {
            if ((uint)shift >= 32)
            {
                context.EmitAsr(31);

                if (setCarry)
                {
                    context.Emit(OpCodes.Dup);

                    context.EmitLdc_I4(1);

                    context.Emit(OpCodes.And);

                    context.EmitStflg((int)PState.CBit);
                }
            }
            else
            {
                if (setCarry)
                {
                    context.Emit(OpCodes.Dup);

                    context.EmitLsr(shift - 1);

                    context.EmitLdc_I4(1);

                    context.Emit(OpCodes.And);

                    context.EmitStflg((int)PState.CBit);
                }

                context.EmitAsr(shift);
            }
        }
예제 #3
0
        private static void EmitCcmp(ILEmitterCtx context, CcmpOp cmpOp)
        {
            OpCodeCcmp64 op = (OpCodeCcmp64)context.CurrOp;

            ILLabel lblTrue = new ILLabel();
            ILLabel lblEnd  = new ILLabel();

            context.EmitCondBranch(lblTrue, op.Cond);

            context.EmitLdc_I4((op.Nzcv >> 0) & 1);

            context.EmitStflg((int)PState.VBit);

            context.EmitLdc_I4((op.Nzcv >> 1) & 1);

            context.EmitStflg((int)PState.CBit);

            context.EmitLdc_I4((op.Nzcv >> 2) & 1);

            context.EmitStflg((int)PState.ZBit);

            context.EmitLdc_I4((op.Nzcv >> 3) & 1);

            context.EmitStflg((int)PState.NBit);

            context.Emit(OpCodes.Br_S, lblEnd);

            context.MarkLabel(lblTrue);

            EmitAluLoadOpers(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);
        }
예제 #4
0
        private static void EmitZeroCvFlags(ILEmitterCtx context)
        {
            context.EmitLdc_I4(0);

            context.EmitStflg((int)PState.VBit);

            context.EmitLdc_I4(0);

            context.EmitStflg((int)PState.CBit);
        }
예제 #5
0
        private static void EmitRrxC(ILEmitterCtx context, bool setCarry)
        {
            // Rotate right by 1 with carry.
            if (setCarry)
            {
                context.Emit(OpCodes.Dup);

                context.EmitLdc_I4(1);

                context.Emit(OpCodes.And);

                context.EmitSttmp();
            }

            context.EmitLsr(1);

            context.EmitLdflg((int)PState.CBit);

            context.EmitLsl(31);

            context.Emit(OpCodes.Or);

            if (setCarry)
            {
                context.EmitLdtmp();
                context.EmitStflg((int)PState.CBit);
            }
        }
예제 #6
0
        private static void Blx(ILEmitterCtx context, bool x)
        {
            IOpCode32BImm op = (IOpCode32BImm)context.CurrOp;

            uint pc = op.GetPc();

            bool isThumb = IsThumb(context.CurrOp);

            if (!isThumb)
            {
                context.EmitLdc_I(op.GetPc() - 4);
            }
            else
            {
                context.EmitLdc_I(op.GetPc() | 1);
            }

            context.EmitStint(GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr));

            //If x is true, then this is a branch with link and exchange.
            //In this case we need to swap the mode between Arm <-> Thumb.
            if (x)
            {
                context.EmitLdc_I4(isThumb ? 0 : 1);

                context.EmitStflg((int)PState.TBit);
            }

            InstEmitFlowHelper.EmitCall(context, op.Imm);
        }
예제 #7
0
        public static void EmitBxWritePc(ILEmitterCtx context)
        {
            context.Emit(OpCodes.Dup);

            context.EmitLdc_I4(1);

            context.Emit(OpCodes.And);
            context.Emit(OpCodes.Dup);

            context.EmitStflg((int)PState.TBit);

            ILLabel lblArmMode = new ILLabel();
            ILLabel lblEnd     = new ILLabel();

            context.Emit(OpCodes.Brtrue_S, lblArmMode);

            context.EmitLdc_I4(~1);

            context.Emit(OpCodes.Br_S, lblEnd);

            context.MarkLabel(lblArmMode);

            context.EmitLdc_I4(~3);

            context.MarkLabel(lblEnd);

            context.Emit(OpCodes.And);
            context.Emit(OpCodes.Conv_U8);
            context.Emit(OpCodes.Ret);
        }
        public static void EmitSetNzcv(ILEmitterCtx context, int nzcv)
        {
            context.EmitLdc_I4((nzcv >> 0) & 1);

            context.EmitStflg((int)PState.VBit);

            context.EmitLdc_I4((nzcv >> 1) & 1);

            context.EmitStflg((int)PState.CBit);

            context.EmitLdc_I4((nzcv >> 2) & 1);

            context.EmitStflg((int)PState.ZBit);

            context.EmitLdc_I4((nzcv >> 3) & 1);

            context.EmitStflg((int)PState.NBit);
        }
예제 #9
0
        public static void EmitAddsCCheck(ILEmitterCtx context)
        {
            // C = Rd < Rn
            context.Emit(OpCodes.Dup);

            EmitAluLoadRn(context);

            context.Emit(OpCodes.Clt_Un);

            context.EmitStflg((int)PState.CBit);
        }
예제 #10
0
        private static void EmitLslC(ILEmitterCtx context, bool setCarry, int shift)
        {
            if ((uint)shift > 32)
            {
                EmitShiftByMoreThan32(context, setCarry);
            }
            else if (shift == 32)
            {
                if (setCarry)
                {
                    context.EmitLdc_I4(1);

                    context.Emit(OpCodes.And);

                    context.EmitStflg((int)PState.CBit);
                }
                else
                {
                    context.Emit(OpCodes.Pop);
                }

                context.EmitLdc_I4(0);
            }
            else
            {
                if (setCarry)
                {
                    context.Emit(OpCodes.Dup);

                    context.EmitLsr(32 - shift);

                    context.EmitLdc_I4(1);

                    context.Emit(OpCodes.And);

                    context.EmitStflg((int)PState.CBit);
                }

                context.EmitLsl(shift);
            }
        }
예제 #11
0
        public static void EmitAluLoadOper2(ILEmitterCtx context, bool setCarry = true)
        {
            switch (context.CurrOp)
            {
            // ARM32.
            case OpCode32AluImm op:
                context.EmitLdc_I4(op.Imm);

                if (op.SetFlags && op.IsRotated)
                {
                    context.EmitLdc_I4((int)((uint)op.Imm >> 31));

                    context.EmitStflg((int)PState.CBit);
                }
                break;

            case OpCode32AluRsImm op:
                EmitLoadRmShiftedByImmediate(context, op, setCarry);
                break;

            case OpCodeT16AluImm8 op:
                context.EmitLdc_I4(op.Imm);
                break;

            // ARM64.
            case IOpCodeAluImm64 op:
                context.EmitLdc_I(op.Imm);
                break;

            case IOpCodeAluRs64 op:
                context.EmitLdintzr(op.Rm);

                switch (op.ShiftType)
                {
                case ShiftType.Lsl: context.EmitLsl(op.Shift); break;

                case ShiftType.Lsr: context.EmitLsr(op.Shift); break;

                case ShiftType.Asr: context.EmitAsr(op.Shift); break;

                case ShiftType.Ror: context.EmitRor(op.Shift); break;
                }
                break;

            case IOpCodeAluRx64 op:
                context.EmitLdintzr(op.Rm);
                context.EmitCast(op.IntType);
                context.EmitLsl(op.Shift);
                break;

            default: throw new InvalidOperationException();
            }
        }
예제 #12
0
        public static void EmitSubsCCheck(ILEmitterCtx context)
        {
            // C = Rn == Rm || Rn > Rm = !(Rn < Rm)
            EmitAluLoadOpers(context);

            context.Emit(OpCodes.Clt_Un);

            context.EmitLdc_I4(1);

            context.Emit(OpCodes.Xor);

            context.EmitStflg((int)PState.CBit);
        }
예제 #13
0
        private static void EmitShiftByMoreThan32(ILEmitterCtx context, bool setCarry)
        {
            context.Emit(OpCodes.Pop);

            context.EmitLdc_I4(0);

            if (setCarry)
            {
                context.Emit(OpCodes.Dup);

                context.EmitStflg((int)PState.CBit);
            }
        }
예제 #14
0
        private static void EmitRorC(ILEmitterCtx context, bool setCarry, int shift)
        {
            shift &= 0x1f;

            context.EmitRor(shift);

            if (setCarry)
            {
                context.Emit(OpCodes.Dup);

                context.EmitLsr(31);

                context.EmitStflg((int)PState.CBit);
            }
        }
예제 #15
0
        public static void EmitSbcsCCheck(ILEmitterCtx context)
        {
            // C = (Rn == Rm && CIn) || Rn > Rm
            EmitAluLoadOpers(context);

            context.Emit(OpCodes.Ceq);

            context.EmitLdflg((int)PState.CBit);

            context.Emit(OpCodes.And);

            EmitAluLoadOpers(context);

            context.Emit(OpCodes.Cgt_Un);
            context.Emit(OpCodes.Or);

            context.EmitStflg((int)PState.CBit);
        }
예제 #16
0
        public static void EmitSubsVCheck(ILEmitterCtx context)
        {
            // V = (Rd ^ Rn) & (Rn ^ Rm) < 0
            context.Emit(OpCodes.Dup);

            EmitAluLoadRn(context);

            context.Emit(OpCodes.Xor);

            EmitAluLoadOpers(context);

            context.Emit(OpCodes.Xor);
            context.Emit(OpCodes.And);

            context.EmitLdc_I(0);

            context.Emit(OpCodes.Clt);

            context.EmitStflg((int)PState.VBit);
        }
예제 #17
0
        public static void EmitAdcsCCheck(ILEmitterCtx context)
        {
            // C = (Rd == Rn && CIn) || Rd < Rn
            context.EmitSttmp();
            context.EmitLdtmp();
            context.EmitLdtmp();

            EmitAluLoadRn(context);

            context.Emit(OpCodes.Ceq);

            context.EmitLdflg((int)PState.CBit);

            context.Emit(OpCodes.And);

            context.EmitLdtmp();

            EmitAluLoadRn(context);

            context.Emit(OpCodes.Clt_Un);
            context.Emit(OpCodes.Or);

            context.EmitStflg((int)PState.CBit);
        }
예제 #18
0
        private static void EmitFcmpOrFcmpe(ILEmitterCtx context, bool signalNaNs)
        {
            OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp;

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

            if (Optimizations.FastFP && Optimizations.UseSse2)
            {
                if (op.Size == 0)
                {
                    Type[] typesCmp = new Type[] { typeof(Vector128 <float>), typeof(Vector128 <float>) };

                    ILLabel lblNaN = new ILLabel();
                    ILLabel lblEnd = new ILLabel();

                    context.EmitLdvec(op.Rn);

                    context.Emit(OpCodes.Dup);
                    context.EmitStvectmp();

                    if (cmpWithZero)
                    {
                        VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero));
                    }
                    else
                    {
                        context.EmitLdvec(op.Rm);
                    }

                    context.Emit(OpCodes.Dup);
                    context.EmitStvectmp2();

                    context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareOrderedScalar), typesCmp));
                    VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero));

                    context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareEqualOrderedScalar), typesCmp));

                    context.Emit(OpCodes.Brtrue_S, lblNaN);

                    context.EmitLdc_I4(0);

                    context.EmitLdvectmp();
                    context.EmitLdvectmp2();
                    context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqualOrderedScalar), typesCmp));

                    context.EmitLdvectmp();
                    context.EmitLdvectmp2();
                    context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareEqualOrderedScalar), typesCmp));

                    context.EmitLdvectmp();
                    context.EmitLdvectmp2();
                    context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareLessThanOrderedScalar), typesCmp));

                    context.EmitStflg((int)PState.NBit);
                    context.EmitStflg((int)PState.ZBit);
                    context.EmitStflg((int)PState.CBit);
                    context.EmitStflg((int)PState.VBit);

                    context.Emit(OpCodes.Br_S, lblEnd);

                    context.MarkLabel(lblNaN);

                    context.EmitLdc_I4(1);
                    context.Emit(OpCodes.Dup);
                    context.EmitLdc_I4(0);
                    context.Emit(OpCodes.Dup);

                    context.EmitStflg((int)PState.NBit);
                    context.EmitStflg((int)PState.ZBit);
                    context.EmitStflg((int)PState.CBit);
                    context.EmitStflg((int)PState.VBit);

                    context.MarkLabel(lblEnd);
                }
                else /* if (op.Size == 1) */
                {
                    Type[] typesCmp = new Type[] { typeof(Vector128 <double>), typeof(Vector128 <double>) };

                    ILLabel lblNaN = new ILLabel();
                    ILLabel lblEnd = new ILLabel();

                    context.EmitLdvec(op.Rn);

                    context.Emit(OpCodes.Dup);
                    context.EmitStvectmp();

                    if (cmpWithZero)
                    {
                        VectorHelper.EmitCall(context, nameof(VectorHelper.VectorDoubleZero));
                    }
                    else
                    {
                        context.EmitLdvec(op.Rm);
                    }

                    context.Emit(OpCodes.Dup);
                    context.EmitStvectmp2();

                    context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareOrderedScalar), typesCmp));
                    VectorHelper.EmitCall(context, nameof(VectorHelper.VectorDoubleZero));

                    context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqualOrderedScalar), typesCmp));

                    context.Emit(OpCodes.Brtrue_S, lblNaN);

                    context.EmitLdc_I4(0);

                    context.EmitLdvectmp();
                    context.EmitLdvectmp2();
                    context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThanOrEqualOrderedScalar), typesCmp));

                    context.EmitLdvectmp();
                    context.EmitLdvectmp2();
                    context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqualOrderedScalar), typesCmp));

                    context.EmitLdvectmp();
                    context.EmitLdvectmp2();
                    context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareLessThanOrderedScalar), typesCmp));

                    context.EmitStflg((int)PState.NBit);
                    context.EmitStflg((int)PState.ZBit);
                    context.EmitStflg((int)PState.CBit);
                    context.EmitStflg((int)PState.VBit);

                    context.Emit(OpCodes.Br_S, lblEnd);

                    context.MarkLabel(lblNaN);

                    context.EmitLdc_I4(1);
                    context.Emit(OpCodes.Dup);
                    context.EmitLdc_I4(0);
                    context.Emit(OpCodes.Dup);

                    context.EmitStflg((int)PState.NBit);
                    context.EmitStflg((int)PState.ZBit);
                    context.EmitStflg((int)PState.CBit);
                    context.EmitStflg((int)PState.VBit);

                    context.MarkLabel(lblEnd);
                }
            }
            else
            {
                EmitVectorExtractF(context, op.Rn, 0, op.Size);

                if (cmpWithZero)
                {
                    if (op.Size == 0)
                    {
                        context.EmitLdc_R4(0f);
                    }
                    else /* if (op.Size == 1) */
                    {
                        context.EmitLdc_R8(0d);
                    }
                }
                else
                {
                    EmitVectorExtractF(context, op.Rm, 0, op.Size);
                }

                context.EmitLdc_I4(!signalNaNs ? 0 : 1);

                EmitSoftFloatCall(context, nameof(SoftFloat32.FPCompare));

                EmitSetNzcv(context);
            }
        }
예제 #19
0
        public static void Fcmp_S(ILEmitterCtx context)
        {
            OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp;

            bool cmpWithZero = !(op is OpCodeSimdFcond64) ? 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);
            }

            ILLabel lblNaN = new ILLabel();
            ILLabel lblEnd = new ILLabel();

            context.Emit(OpCodes.Brtrue_S, lblNaN);

            void EmitLoadOpers()
            {
                EmitVectorExtractF(context, op.Rn, 0, op.Size);

                if (cmpWithZero)
                {
                    if (op.Size == 0)
                    {
                        context.EmitLdc_R4(0f);
                    }
                    else /* if (Op.Size == 1) */
                    {
                        context.EmitLdc_R8(0d);
                    }
                }
                else
                {
                    EmitVectorExtractF(context, op.Rm, 0, op.Size);
                }
            }

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

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

            context.EmitStflg((int)PState.ZBit);

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

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

            context.EmitStflg((int)PState.CBit);

            //N = Rn < Rm
            EmitLoadOpers();

            context.Emit(OpCodes.Clt);

            context.EmitStflg((int)PState.NBit);

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

            context.EmitStflg((int)PState.VBit);

            context.Emit(OpCodes.Br_S, lblEnd);

            context.MarkLabel(lblNaN);

            EmitSetNzcv(context, 0b0011);

            context.MarkLabel(lblEnd);
        }