Пример #1
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);
            }
        }
Пример #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
        public static void EmitDataLoadOper2(ILEmitterCtx context)
        {
            switch (context.CurrOp)
            {
            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;
            }
        }
Пример #4
0
        public static void Bfm(ILEmitterCtx context)
        {
            OpCodeBfm64 op = (OpCodeBfm64)context.CurrOp;

            if (op.Pos < op.Shift)
            {
                //BFI.
                context.EmitLdintzr(op.Rn);

                int shift = op.GetBitsCount() - op.Shift;

                int width = op.Pos + 1;

                long mask = (long)(ulong.MaxValue >> (64 - width));

                context.EmitLdc_I(mask);

                context.Emit(OpCodes.And);

                context.EmitLsl(shift);

                context.EmitLdintzr(op.Rd);

                context.EmitLdc_I(~(mask << shift));

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

                context.EmitStintzr(op.Rd);
            }
            else
            {
                //BFXIL.
                context.EmitLdintzr(op.Rn);

                context.EmitLsr(op.Shift);

                int width = op.Pos - op.Shift + 1;

                long mask = (long)(ulong.MaxValue >> (64 - width));

                context.EmitLdc_I(mask);

                context.Emit(OpCodes.And);

                context.EmitLdintzr(op.Rd);

                context.EmitLdc_I(~mask);

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

                context.EmitStintzr(op.Rd);
            }
        }
Пример #5
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();
            }
        }
Пример #6
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);
            }
        }
Пример #7
0
        private static void EmitLsrC(ILEmitterCtx context, bool setCarry, int shift)
        {
            if ((uint)shift > 32)
            {
                EmitShiftByMoreThan32(context, setCarry);
            }
            else if (shift == 32)
            {
                if (setCarry)
                {
                    context.EmitLsr(31);

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

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

                context.EmitLsr(shift - 1);

                context.EmitLdc_I4(1);

                context.Emit(OpCodes.And);

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

                context.EmitLsr(shift);
            }
        }
Пример #8
0
        private static void EmitBfiz(ILEmitterCtx context, bool signed)
        {
            OpCodeBfm64 op = (OpCodeBfm64)context.CurrOp;

            int width = op.Pos + 1;

            context.EmitLdintzr(op.Rn);

            context.EmitLsl(op.GetBitsCount() - width);

            if (signed)
            {
                context.EmitAsr(op.Shift - width);
            }
            else
            {
                context.EmitLsr(op.Shift - width);
            }

            context.EmitStintzr(op.Rd);
        }
Пример #9
0
        private static void EmitPtPointerLoad(ILEmitterCtx context, ILLabel lblFallbackPath)
        {
            context.EmitLdc_I8(context.Memory.PageTable.ToInt64());

            context.Emit(OpCodes.Conv_I);

            int bit = MemoryManager.PageBits;

            do
            {
                context.EmitLdint(_tempIntAddress);

                if (context.CurrOp.RegisterSize == RegisterSize.Int32)
                {
                    context.Emit(OpCodes.Conv_U8);
                }

                context.EmitLsr(bit);

                bit += context.Memory.PtLevelBits;

                if (bit < context.Memory.AddressSpaceBits)
                {
                    context.EmitLdc_I8(context.Memory.PtLevelMask);

                    context.Emit(OpCodes.And);
                }

                context.EmitLdc_I8(IntPtr.Size);

                context.Emit(OpCodes.Mul);
                context.Emit(OpCodes.Conv_I);
                context.Emit(OpCodes.Add);
                context.Emit(OpCodes.Ldind_I);
            }while (bit < context.Memory.AddressSpaceBits);

            if (!context.Memory.HasWriteWatchSupport)
            {
                context.Emit(OpCodes.Conv_U8);

                context.EmitStint(_tempIntPtAddr);
                context.EmitLdint(_tempIntPtAddr);

                context.EmitLdc_I8(MemoryManager.PteFlagsMask);

                context.Emit(OpCodes.And);

                context.Emit(OpCodes.Brtrue, lblFallbackPath);

                context.EmitLdint(_tempIntPtAddr);

                context.Emit(OpCodes.Conv_I);
            }

            context.EmitLdint(_tempIntAddress);

            context.EmitLdc_I(MemoryManager.PageMask);

            context.Emit(OpCodes.And);
            context.Emit(OpCodes.Conv_I);
            context.Emit(OpCodes.Add);
        }
Пример #10
0
        private static void EmitLoadOrStore(ILEmitterCtx context, int size, AccessType accType)
        {
            OpCode32Mem op = (OpCode32Mem)context.CurrOp;

            if (op.Index || op.WBack)
            {
                EmitLoadFromRegister(context, op.Rn);

                context.EmitLdc_I4(op.Imm);

                context.Emit(op.Add ? OpCodes.Add : OpCodes.Sub);

                context.EmitSttmp();
            }

            if (op.Index)
            {
                context.EmitLdtmp();
            }
            else
            {
                EmitLoadFromRegister(context, op.Rn);
            }

            if ((accType & AccessType.Load) != 0)
            {
                if ((accType & AccessType.Signed) != 0)
                {
                    EmitReadSx32Call(context, size);
                }
                else
                {
                    EmitReadZxCall(context, size);
                }

                if (op.WBack)
                {
                    context.EmitLdtmp();

                    EmitStoreToRegister(context, op.Rn);
                }

                if (size == DWordSizeLog2)
                {
                    context.Emit(OpCodes.Dup);

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

                    ILLabel lblBigEndian = new ILLabel();
                    ILLabel lblEnd       = new ILLabel();

                    context.Emit(OpCodes.Brtrue_S, lblBigEndian);

                    //Little endian mode.
                    context.Emit(OpCodes.Conv_U4);

                    EmitStoreToRegister(context, op.Rt);

                    context.EmitLsr(32);

                    context.Emit(OpCodes.Conv_U4);

                    EmitStoreToRegister(context, op.Rt | 1);

                    context.Emit(OpCodes.Br_S, lblEnd);

                    //Big endian mode.
                    context.MarkLabel(lblBigEndian);

                    context.EmitLsr(32);

                    context.Emit(OpCodes.Conv_U4);

                    EmitStoreToRegister(context, op.Rt);

                    context.Emit(OpCodes.Conv_U4);

                    EmitStoreToRegister(context, op.Rt | 1);

                    context.MarkLabel(lblEnd);
                }
                else
                {
                    EmitStoreToRegister(context, op.Rt);
                }
            }
            else
            {
                if (op.WBack)
                {
                    context.EmitLdtmp();

                    EmitStoreToRegister(context, op.Rn);
                }

                EmitLoadFromRegister(context, op.Rt);

                if (size == DWordSizeLog2)
                {
                    context.Emit(OpCodes.Conv_U8);

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

                    ILLabel lblBigEndian = new ILLabel();
                    ILLabel lblEnd       = new ILLabel();

                    context.Emit(OpCodes.Brtrue_S, lblBigEndian);

                    //Little endian mode.
                    EmitLoadFromRegister(context, op.Rt | 1);

                    context.Emit(OpCodes.Conv_U8);

                    context.EmitLsl(32);

                    context.Emit(OpCodes.Or);

                    context.Emit(OpCodes.Br_S, lblEnd);

                    //Big endian mode.
                    context.MarkLabel(lblBigEndian);

                    context.EmitLsl(32);

                    EmitLoadFromRegister(context, op.Rt | 1);

                    context.Emit(OpCodes.Conv_U8);

                    context.Emit(OpCodes.Or);

                    context.MarkLabel(lblEnd);
                }

                EmitWriteCall(context, size);
            }
        }
Пример #11
0
        private static void EmitLoad(ILEmitterCtx context, AccessType accType, bool pair)
        {
            OpCodeMemEx64 op = (OpCodeMemEx64)context.CurrOp;

            bool ordered   = (accType & AccessType.Ordered) != 0;
            bool exclusive = (accType & AccessType.Exclusive) != 0;

            if (ordered)
            {
                EmitBarrier(context);
            }

            context.EmitLdint(op.Rn);
            context.EmitSttmp();

            if (exclusive)
            {
                context.EmitLdarg(TranslatedSub.StateArgIdx);
                context.EmitLdtmp();

                context.EmitPrivateCall(typeof(CpuThreadState), nameof(CpuThreadState.SetExclusiveAddress));
            }

            void WriteExclusiveValue(string propName)
            {
                if (op.Size < 3)
                {
                    context.Emit(OpCodes.Conv_U8);
                }

                context.EmitSttmp2();
                context.EmitLdarg(TranslatedSub.StateArgIdx);
                context.EmitLdtmp2();

                context.EmitCallPrivatePropSet(typeof(CpuThreadState), propName);

                context.EmitLdtmp2();

                if (op.Size < 3)
                {
                    context.Emit(OpCodes.Conv_U4);
                }
            }

            if (pair)
            {
                //Exclusive loads should be atomic. For pairwise loads, we need to
                //read all the data at once. For a 32-bits pairwise load, we do a
                //simple 64-bits load, for a 128-bits load, we need to call a special
                //method to read 128-bits atomically.
                if (op.Size == 2)
                {
                    context.EmitLdarg(TranslatedSub.MemoryArgIdx);
                    context.EmitLdtmp();

                    EmitReadZxCall(context, 3);

                    context.Emit(OpCodes.Dup);

                    //Mask low half.
                    context.Emit(OpCodes.Conv_U4);

                    if (exclusive)
                    {
                        WriteExclusiveValue(nameof(CpuThreadState.ExclusiveValueLow));
                    }

                    context.EmitStintzr(op.Rt);

                    //Shift high half.
                    context.EmitLsr(32);
                    context.Emit(OpCodes.Conv_U4);

                    if (exclusive)
                    {
                        WriteExclusiveValue(nameof(CpuThreadState.ExclusiveValueHigh));
                    }

                    context.EmitStintzr(op.Rt2);
                }
                else if (op.Size == 3)
                {
                    context.EmitLdarg(TranslatedSub.MemoryArgIdx);
                    context.EmitLdtmp();

                    context.EmitPrivateCall(typeof(MemoryManager), nameof(MemoryManager.AtomicReadInt128));

                    context.Emit(OpCodes.Dup);

                    //Load low part of the vector.
                    context.EmitLdc_I4(0);
                    context.EmitLdc_I4(3);

                    VectorHelper.EmitCall(context, nameof(VectorHelper.VectorExtractIntZx));

                    if (exclusive)
                    {
                        WriteExclusiveValue(nameof(CpuThreadState.ExclusiveValueLow));
                    }

                    context.EmitStintzr(op.Rt);

                    //Load high part of the vector.
                    context.EmitLdc_I4(1);
                    context.EmitLdc_I4(3);

                    VectorHelper.EmitCall(context, nameof(VectorHelper.VectorExtractIntZx));

                    if (exclusive)
                    {
                        WriteExclusiveValue(nameof(CpuThreadState.ExclusiveValueHigh));
                    }

                    context.EmitStintzr(op.Rt2);
                }
                else
                {
                    throw new InvalidOperationException($"Invalid store size of {1 << op.Size} bytes.");
                }
            }
            else
            {
                //8, 16, 32 or 64-bits (non-pairwise) load.
                context.EmitLdarg(TranslatedSub.MemoryArgIdx);
                context.EmitLdtmp();

                EmitReadZxCall(context, op.Size);

                if (exclusive)
                {
                    WriteExclusiveValue(nameof(CpuThreadState.ExclusiveValueLow));
                }

                context.EmitStintzr(op.Rt);
            }
        }