Ejemplo n.º 1
0
        public static void Aesd_V(ArmEmitterContext context)
        {
            OpCodeSimd op = (OpCodeSimd)context.CurrOp;

            Operand d = GetVec(op.Rd);
            Operand n = GetVec(op.Rn);

            Operand res;

            if (Optimizations.UseAesni)
            {
                res = context.AddIntrinsic(Intrinsic.X86Aesdeclast, context.AddIntrinsic(Intrinsic.X86Xorpd, d, n), context.VectorZero());
            }
            else
            {
                res = context.Call(new _V128_V128_V128(SoftFallback.Decrypt), d, n);
            }

            context.Copy(d, res);
        }
Ejemplo n.º 2
0
        public static void Urshl_V(ArmEmitterContext context)
        {
            OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;

            Operand res = context.VectorZero();

            int elems = op.GetBytesCount() >> op.Size;

            for (int index = 0; index < elems; index++)
            {
                Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size);
                Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size);

                Operand e = context.Call(new _U64_U64_U64_Bool_S32(SoftFallback.UnsignedShlReg), ne, me, Const(1), Const(op.Size));

                res = EmitVectorInsert(context, res, e, index, op.Size);
            }

            context.Copy(GetVec(op.Rd), res);
        }
Ejemplo n.º 3
0
        public static void Sshl_V(ArmEmitterContext context)
        {
            OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;

            Operand res = context.VectorZero();

            int elems = op.GetBytesCount() >> op.Size;

            for (int index = 0; index < elems; index++)
            {
                Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size);
                Operand me = EmitVectorExtractSx(context, op.Rm, index, op.Size);

                Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlReg)), ne, me, Const(0), Const(op.Size));

                res = EmitVectorInsert(context, res, e, index, op.Size);
            }

            context.Copy(GetVec(op.Rd), res);
        }
Ejemplo n.º 4
0
        public static void EmitTailContinue(ArmEmitterContext context, Operand address, bool allowRejit = false)
        {
            bool useTailContinue = true; // Left option here as it may be useful if we need to return to managed rather than tail call in future. (eg. for debug)

            if (useTailContinue)
            {
                if (allowRejit)
                {
                    address = context.BitwiseOr(address, Const(1L));
                }

                Operand fallbackAddr = context.Call(new _U64_U64(NativeInterface.GetFunctionAddress), address);

                EmitNativeCall(context, fallbackAddr, true);
            }
            else
            {
                context.Return(address);
            }
        }
Ejemplo n.º 5
0
        public static void Aese_V(ArmEmitterContext context)
        {
            OpCodeSimd op = (OpCodeSimd)context.CurrOp;

            Operand d = GetVec(op.Rd);
            Operand n = GetVec(op.Rn);

            Operand res;

            if (Optimizations.UseAesni)
            {
                res = context.AddIntrinsic(Intrinsic.X86Aesenclast, context.AddIntrinsic(Intrinsic.X86Xorpd, d, n), context.VectorZero());
            }
            else
            {
                res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Encrypt)), d, n);
            }

            context.Copy(d, res);
        }
Ejemplo n.º 6
0
        public static Operand EmitLoadExclusive(
            ArmEmitterContext context,
            Operand address,
            bool exclusive,
            int size)
        {
            Delegate fallbackMethodDlg = null;

            if (exclusive)
            {
                switch (size)
                {
                case 0: fallbackMethodDlg = new _U8_U64(NativeInterface.ReadByteExclusive); break;

                case 1: fallbackMethodDlg = new _U16_U64(NativeInterface.ReadUInt16Exclusive); break;

                case 2: fallbackMethodDlg = new _U32_U64(NativeInterface.ReadUInt32Exclusive); break;

                case 3: fallbackMethodDlg = new _U64_U64(NativeInterface.ReadUInt64Exclusive); break;

                case 4: fallbackMethodDlg = new _V128_U64(NativeInterface.ReadVector128Exclusive); break;
                }
            }
            else
            {
                switch (size)
                {
                case 0: fallbackMethodDlg = new _U8_U64(NativeInterface.ReadByte); break;

                case 1: fallbackMethodDlg = new _U16_U64(NativeInterface.ReadUInt16); break;

                case 2: fallbackMethodDlg = new _U32_U64(NativeInterface.ReadUInt32); break;

                case 3: fallbackMethodDlg = new _U64_U64(NativeInterface.ReadUInt64); break;

                case 4: fallbackMethodDlg = new _V128_U64(NativeInterface.ReadVector128); break;
                }
            }

            return(context.Call(fallbackMethodDlg, address));
        }
Ejemplo n.º 7
0
        public static Operand EmitLoadExclusive(
            ArmEmitterContext context,
            Operand address,
            bool exclusive,
            int size)
        {
            MethodInfo info = null;

            if (exclusive)
            {
                switch (size)
                {
                case 0: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByteExclusive));      break;

                case 1: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16Exclusive));    break;

                case 2: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32Exclusive));    break;

                case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64Exclusive));    break;

                case 4: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128Exclusive)); break;
                }
            }
            else
            {
                switch (size)
                {
                case 0: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte));      break;

                case 1: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16));    break;

                case 2: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32));    break;

                case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64));    break;

                case 4: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)); break;
                }
            }

            return(context.Call(info, address));
        }
Ejemplo n.º 8
0
        public static void Msr(ArmEmitterContext context)
        {
            OpCodeSystem op = (OpCodeSystem)context.CurrOp;

            MethodInfo info;

            switch (GetPackedId(op))
            {
            case 0b11_011_0100_0010_000: EmitSetNzcv(context);                                                          return;

            case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpcr));     break;

            case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsr));     break;

            case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)); break;

            default: throw new NotImplementedException($"Unknown MSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
            }

            context.Call(info, GetIntOrZR(context, op.Rt));
        }
Ejemplo n.º 9
0
        public static void Msr(ArmEmitterContext context)
        {
            OpCodeSystem op = (OpCodeSystem)context.CurrOp;

            Delegate dlg;

            switch (GetPackedId(op))
            {
            case 0b11_011_0100_0010_000: EmitSetNzcv(context);                             return;

            case 0b11_011_0100_0100_000: dlg = new _Void_U64(NativeInterface.SetFpcr);     break;

            case 0b11_011_0100_0100_001: dlg = new _Void_U64(NativeInterface.SetFpsr);     break;

            case 0b11_011_1101_0000_010: dlg = new _Void_U64(NativeInterface.SetTpidrEl0); break;

            default: throw new NotImplementedException($"Unknown MSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
            }

            context.Call(dlg, GetIntOrZR(context, op.Rt));
        }
Ejemplo n.º 10
0
        public static void Mrrc(ArmEmitterContext context)
        {
            OpCode32System op = (OpCode32System)context.CurrOp;

            if (op.Coproc != 15)
            {
                InstEmit.Und(context);

                return;
            }

            int opc = op.MrrcOp;

            MethodInfo info;

            switch (op.CRm)
            {
            case 14:     // Timer.
                switch (opc)
                {
                case 0:
                    info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)); break;

                default:
                    throw new NotImplementedException($"Unknown MRRC Opc1 0x{opc:X16} at 0x{op.Address:X16}.");
                }

                break;

            default:
                throw new NotImplementedException($"Unknown MRRC 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
            }

            Operand result = context.Call(info);

            SetIntA32(context, op.Rt, context.ConvertI64ToI32(result));
            SetIntA32(context, op.CRn, context.ConvertI64ToI32(context.ShiftRightUI(result, Const(32))));
        }
        private static void EmitReadVectorFallback(
            ArmEmitterContext context,
            Operand address,
            Operand vector,
            int rt,
            int elem,
            int size)
        {
            Delegate fallbackMethodDlg = null;

            switch (size)
            {
            case 0: fallbackMethodDlg = new _U8_U64(NativeInterface.ReadByte);      break;

            case 1: fallbackMethodDlg = new _U16_U64(NativeInterface.ReadUInt16);    break;

            case 2: fallbackMethodDlg = new _U32_U64(NativeInterface.ReadUInt32);    break;

            case 3: fallbackMethodDlg = new _U64_U64(NativeInterface.ReadUInt64);    break;

            case 4: fallbackMethodDlg = new _V128_U64(NativeInterface.ReadVector128); break;
            }

            Operand value = context.Call(fallbackMethodDlg, address);

            switch (size)
            {
            case 0: value = context.VectorInsert8(vector, value, elem); break;

            case 1: value = context.VectorInsert16(vector, value, elem); break;

            case 2: value = context.VectorInsert(vector, value, elem); break;

            case 3: value = context.VectorInsert(vector, value, elem); break;
            }

            context.Copy(GetVec(rt), value);
        }
Ejemplo n.º 12
0
        private static void EmitReadVectorFallback(
            ArmEmitterContext context,
            Operand address,
            Operand vector,
            int rt,
            int elem,
            int size)
        {
            MethodInfo info = null;

            switch (size)
            {
            case 0: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte));      break;

            case 1: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16));    break;

            case 2: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32));    break;

            case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64));    break;

            case 4: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)); break;
            }

            Operand value = context.Call(info, address);

            switch (size)
            {
            case 0: value = context.VectorInsert8(vector, value, elem); break;

            case 1: value = context.VectorInsert16(vector, value, elem); break;

            case 2: value = context.VectorInsert(vector, value, elem); break;

            case 3: value = context.VectorInsert(vector, value, elem); break;
            }

            context.Copy(GetVec(rt), value);
        }
Ejemplo n.º 13
0
        private static Operand EmitSatQ(ArmEmitterContext context, Operand value, int eSize, bool signed)
        {
            Debug.Assert(eSize <= 32);

            long intMin = signed ? -(1L << (eSize - 1)) : 0;
            long intMax = signed ? (1L << (eSize - 1)) - 1 : (1L << eSize) - 1;

            Operand gt = context.ICompareGreater(value, Const(value.Type, intMax));
            Operand lt = context.ICompareLess(value, Const(value.Type, intMin));

            value = context.ConditionalSelect(gt, Const(value.Type, intMax), value);
            value = context.ConditionalSelect(lt, Const(value.Type, intMin), value);

            Operand lblNoSat = Label();

            context.BranchIfFalse(lblNoSat, context.BitwiseOr(gt, lt));

            context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));

            context.MarkLabel(lblNoSat);

            return(value);
        }
Ejemplo n.º 14
0
        public static void Rbit_V(ArmEmitterContext context)
        {
            OpCodeSimd op = (OpCodeSimd)context.CurrOp;

            Operand res = context.VectorZero();

            int elems = op.RegisterSize == RegisterSize.Simd128 ? 16 : 8;

            for (int index = 0; index < elems; index++)
            {
                Operand ne = EmitVectorExtractZx(context, op.Rn, index, 0);

                ne = context.ConvertI64ToI32(ne);

                Operand de = context.Call(new _U32_U32(SoftFallback.ReverseBits8), ne);

                de = context.ZeroExtend32(OperandType.I64, de);

                res = EmitVectorInsert(context, res, de, index, 0);
            }

            context.Copy(GetVec(op.Rd), res);
        }
        private static void EmitWriteIntFallback(ArmEmitterContext context, Operand address, int rt, int size)
        {
            Delegate fallbackMethodDlg = null;

            switch (size)
            {
            case 0: fallbackMethodDlg = new _Void_U64_U8(NativeInterface.WriteByte);   break;

            case 1: fallbackMethodDlg = new _Void_U64_U16(NativeInterface.WriteUInt16); break;

            case 2: fallbackMethodDlg = new _Void_U64_U32(NativeInterface.WriteUInt32); break;

            case 3: fallbackMethodDlg = new _Void_U64_U64(NativeInterface.WriteUInt64); break;
            }

            Operand value = GetInt(context, rt);

            if (size < 3 && value.Type == OperandType.I64)
            {
                value = context.ConvertI64ToI32(value);
            }

            context.Call(fallbackMethodDlg, address, value);
        }
Ejemplo n.º 16
0
        private static void EmitWriteIntFallback(ArmEmitterContext context, Operand address, int rt, int size)
        {
            MethodInfo info = null;

            switch (size)
            {
            case 0: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte));   break;

            case 1: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16)); break;

            case 2: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32)); break;

            case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64)); break;
            }

            Operand value = GetInt(context, rt);

            if (size < 3 && value.Type == OperandType.I64)
            {
                value = context.ConvertI64ToI32(value);
            }

            context.Call(info, address, value);
        }
Ejemplo n.º 17
0
 public static void Clrex(ArmEmitterContext context)
 {
     context.Call(new _Void(NativeInterface.ClearExclusive));
 }
Ejemplo n.º 18
0
        private static void EmitTableVectorLookup(ArmEmitterContext context, bool isTbl)
        {
            OpCodeSimdTbl op = (OpCodeSimdTbl)context.CurrOp;

            if (Optimizations.UseSsse3)
            {
                Operand d = GetVec(op.Rd);
                Operand m = GetVec(op.Rm);

                Operand res;

                Operand mask = X86GetAllElements(context, 0x0F0F0F0F0F0F0F0FL);

                // Fast path for single register table.
                {
                    Operand n = GetVec(op.Rn);

                    Operand mMask = context.AddIntrinsic(Intrinsic.X86Pcmpgtb, m, mask);
                    mMask = context.AddIntrinsic(Intrinsic.X86Por, mMask, m);

                    res = context.AddIntrinsic(Intrinsic.X86Pshufb, n, mMask);
                }

                for (int index = 1; index < op.Size; index++)
                {
                    Operand ni = GetVec((op.Rn + index) & 0x1F);

                    Operand idxMask = X86GetAllElements(context, 0x1010101010101010L * index);

                    Operand mSubMask = context.AddIntrinsic(Intrinsic.X86Psubb, m, idxMask);

                    Operand mMask = context.AddIntrinsic(Intrinsic.X86Pcmpgtb, mSubMask, mask);
                    mMask = context.AddIntrinsic(Intrinsic.X86Por, mMask, mSubMask);

                    Operand res2 = context.AddIntrinsic(Intrinsic.X86Pshufb, ni, mMask);

                    res = context.AddIntrinsic(Intrinsic.X86Por, res, res2);
                }

                if (!isTbl)
                {
                    Operand idxMask  = X86GetAllElements(context, (0x1010101010101010L * op.Size) - 0x0101010101010101L);
                    Operand zeroMask = context.VectorZero();

                    Operand mPosMask = context.AddIntrinsic(Intrinsic.X86Pcmpgtb, m, idxMask);
                    Operand mNegMask = context.AddIntrinsic(Intrinsic.X86Pcmpgtb, zeroMask, m);

                    Operand mMask = context.AddIntrinsic(Intrinsic.X86Por, mPosMask, mNegMask);

                    Operand dMask = context.AddIntrinsic(Intrinsic.X86Pand, d, mMask);

                    res = context.AddIntrinsic(Intrinsic.X86Por, res, dMask);
                }

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

                context.Copy(d, res);
            }
            else
            {
                Operand d = GetVec(op.Rd);

                List <Operand> args = new List <Operand>();

                if (!isTbl)
                {
                    args.Add(d);
                }

                args.Add(GetVec(op.Rm));

                args.Add(Const(op.RegisterSize == RegisterSize.Simd64 ? 8 : 16));

                for (int index = 0; index < op.Size; index++)
                {
                    args.Add(GetVec((op.Rn + index) & 0x1F));
                }

                Delegate dlg = null;

                switch (op.Size)
                {
                case 1: dlg = isTbl
                        ? (Delegate) new _V128_V128_S32_V128(SoftFallback.Tbl1)
                        : (Delegate) new _V128_V128_V128_S32_V128(SoftFallback.Tbx1);
                    break;

                case 2: dlg = isTbl
                        ? (Delegate) new _V128_V128_S32_V128_V128(SoftFallback.Tbl2)
                        : (Delegate) new _V128_V128_V128_S32_V128_V128(SoftFallback.Tbx2);
                    break;

                case 3: dlg = isTbl
                        ? (Delegate) new _V128_V128_S32_V128_V128_V128(SoftFallback.Tbl3)
                        : (Delegate) new _V128_V128_V128_S32_V128_V128_V128(SoftFallback.Tbx3);
                    break;

                case 4: dlg = isTbl
                        ? (Delegate) new _V128_V128_S32_V128_V128_V128_V128(SoftFallback.Tbl4)
                        : (Delegate) new _V128_V128_V128_S32_V128_V128_V128_V128(SoftFallback.Tbx4);
                    break;
                }

                context.Copy(d, context.Call(dlg, args.ToArray()));
            }
        }
Ejemplo n.º 19
0
        public static void Tbl_V(ArmEmitterContext context)
        {
            OpCodeSimdTbl op = (OpCodeSimdTbl)context.CurrOp;

            if (Optimizations.UseSsse3)
            {
                Operand n = GetVec(op.Rn);
                Operand m = GetVec(op.Rm);

                Operand mask = X86GetAllElements(context, 0x0F0F0F0F0F0F0F0FL);

                Operand mMask = context.AddIntrinsic(Intrinsic.X86Pcmpgtb, m, mask);

                mMask = context.AddIntrinsic(Intrinsic.X86Por, mMask, m);

                Operand res = context.AddIntrinsic(Intrinsic.X86Pshufb, n, mMask);

                for (int index = 1; index < op.Size; index++)
                {
                    Operand ni = GetVec((op.Rn + index) & 0x1f);

                    Operand indexMask = X86GetAllElements(context, 0x1010101010101010L * index);

                    Operand mMinusMask = context.AddIntrinsic(Intrinsic.X86Psubb, m, indexMask);

                    Operand mMask2 = context.AddIntrinsic(Intrinsic.X86Pcmpgtb, mMinusMask, mask);

                    mMask2 = context.AddIntrinsic(Intrinsic.X86Por, mMask2, mMinusMask);

                    Operand res2 = context.AddIntrinsic(Intrinsic.X86Pshufb, ni, mMask2);

                    res = context.AddIntrinsic(Intrinsic.X86Por, res, res2);
                }

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

                context.Copy(GetVec(op.Rd), res);
            }
            else
            {
                Operand[] args = new Operand[1 + op.Size];

                args[0] = GetVec(op.Rm);

                for (int index = 0; index < op.Size; index++)
                {
                    args[1 + index] = GetVec((op.Rn + index) & 0x1f);
                }

                Delegate dlg = null;

                switch (op.Size)
                {
                case 1: dlg = op.RegisterSize == RegisterSize.Simd64
                        ? (Delegate) new _V128_V128_V128(SoftFallback.Tbl1_V64)
                        : (Delegate) new _V128_V128_V128(SoftFallback.Tbl1_V128); break;

                case 2: dlg = op.RegisterSize == RegisterSize.Simd64
                        ? (Delegate) new _V128_V128_V128_V128(SoftFallback.Tbl2_V64)
                        : (Delegate) new _V128_V128_V128_V128(SoftFallback.Tbl2_V128); break;

                case 3: dlg = op.RegisterSize == RegisterSize.Simd64
                        ? (Delegate) new _V128_V128_V128_V128_V128(SoftFallback.Tbl3_V64)
                        : (Delegate) new _V128_V128_V128_V128_V128(SoftFallback.Tbl3_V128); break;

                case 4: dlg = op.RegisterSize == RegisterSize.Simd64
                        ? (Delegate) new _V128_V128_V128_V128_V128_V128(SoftFallback.Tbl4_V64)
                        : (Delegate) new _V128_V128_V128_V128_V128_V128(SoftFallback.Tbl4_V128); break;
                }

                context.Copy(GetVec(op.Rd), context.Call(dlg, args));
            }
        }
Ejemplo n.º 20
0
        public static void EmitStoreExclusive(
            ArmEmitterContext context,
            Operand address,
            Operand value,
            bool exclusive,
            int size,
            int rs,
            bool a32)
        {
            if (size < 3)
            {
                value = context.ConvertI64ToI32(value);
            }

            if (exclusive)
            {
                void SetRs(Operand value)
                {
                    if (a32)
                    {
                        SetIntA32(context, rs, value);
                    }
                    else
                    {
                        SetIntOrZR(context, rs, value);
                    }
                }

                Operand arg0 = context.LoadArgument(OperandType.I64, 0);

                Operand exAddrPtr = context.Add(arg0, Const((long)NativeContext.GetExclusiveAddressOffset()));
                Operand exAddr    = context.Load(address.Type, exAddrPtr);

                // STEP 1: Check if we have exclusive access to this memory region. If not, fail and skip store.
                Operand maskedAddress = context.BitwiseAnd(address, Const(address.Type, GetExclusiveAddressMask()));

                Operand exFailed = context.ICompareNotEqual(exAddr, maskedAddress);

                Operand lblExit = Label();

                SetRs(exFailed);

                context.BranchIfTrue(lblExit, exFailed);

                // STEP 2: We have exclusive access, make sure that the address is valid.
                Operand isUnalignedAddr = InstEmitMemoryHelper.EmitAddressCheck(context, address, size);

                Operand lblFastPath = Label();

                context.BranchIfFalse(lblFastPath, isUnalignedAddr);

                // The call is not expected to return (it should throw).
                context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)), address);

                // STEP 3: We have exclusive access and the address is valid, attempt the store using CAS.
                context.MarkLabel(lblFastPath);

                Operand physAddr = InstEmitMemoryHelper.EmitPtPointerLoad(context, address, null, write: true);

                Operand exValuePtr = context.Add(arg0, Const((long)NativeContext.GetExclusiveValueOffset()));
                Operand exValue    = size switch
                {
                    0 => context.Load8(exValuePtr),
                    1 => context.Load16(exValuePtr),
                    2 => context.Load(OperandType.I32, exValuePtr),
                    3 => context.Load(OperandType.I64, exValuePtr),
                    _ => context.Load(OperandType.V128, exValuePtr)
                };

                Operand currValue = size switch
                {
                    0 => context.CompareAndSwap8(physAddr, exValue, value),
                    1 => context.CompareAndSwap16(physAddr, exValue, value),
                    _ => context.CompareAndSwap(physAddr, exValue, value)
                };

                // STEP 4: Check if we succeeded by comparing expected and in-memory values.
                Operand storeFailed;

                if (size == 4)
                {
                    Operand currValueLow  = context.VectorExtract(OperandType.I64, currValue, 0);
                    Operand currValueHigh = context.VectorExtract(OperandType.I64, currValue, 1);

                    Operand exValueLow  = context.VectorExtract(OperandType.I64, exValue, 0);
                    Operand exValueHigh = context.VectorExtract(OperandType.I64, exValue, 1);

                    storeFailed = context.BitwiseOr(
                        context.ICompareNotEqual(currValueLow, exValueLow),
                        context.ICompareNotEqual(currValueHigh, exValueHigh));
                }
                else
                {
                    storeFailed = context.ICompareNotEqual(currValue, exValue);
                }

                SetRs(storeFailed);

                context.MarkLabel(lblExit);
            }
            else
            {
                InstEmitMemoryHelper.EmitWriteIntAligned(context, address, value, size);
            }
        }
Ejemplo n.º 21
0
        // VCVT (floating-point to integer, floating-point) | VCVT (integer to floating-point, floating-point).
        public static void Vcvt_FI(ArmEmitterContext context)
        {
            OpCode32SimdCvtFI op = (OpCode32SimdCvtFI)context.CurrOp;

            bool toInteger = (op.Opc2 & 0b100) != 0;

            OperandType floatSize = op.RegisterSize == RegisterSize.Int64 ? OperandType.FP64 : OperandType.FP32;

            if (toInteger)
            {
                bool unsigned       = (op.Opc2 & 1) == 0;
                bool roundWithFpscr = op.Opc != 1;

                if (!roundWithFpscr && Optimizations.UseSse41)
                {
                    EmitSse41ConvertInt32(context, FPRoundingMode.TowardsZero, !unsigned);
                }
                else
                {
                    Operand toConvert = ExtractScalar(context, floatSize, op.Vm);

                    Operand asInteger;

                    // TODO: Fast Path.
                    if (roundWithFpscr)
                    {
                        MethodInfo info;

                        if (floatSize == OperandType.FP64)
                        {
                            info = unsigned
                                ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToUInt32))
                                : typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToInt32));
                        }
                        else
                        {
                            info = unsigned
                                ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToUInt32))
                                : typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToInt32));
                        }

                        asInteger = context.Call(info, toConvert);
                    }
                    else
                    {
                        // Round towards zero.
                        asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned);
                    }

                    InsertScalar(context, op.Vd, asInteger);
                }
            }
            else
            {
                bool unsigned = op.Opc == 0;

                Operand toConvert = ExtractScalar(context, OperandType.I32, op.Vm);

                Operand asFloat = EmitFPConvert(context, toConvert, floatSize, !unsigned);

                InsertScalar(context, op.Vd, asFloat);
            }
        }
Ejemplo n.º 22
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 cf = context.AddIntrinsicInt(Intrinsic.X86Comissge, n, m);
                    Operand zf = context.AddIntrinsicInt(Intrinsic.X86Comisseq, n, m);
                    Operand nf = context.AddIntrinsicInt(Intrinsic.X86Comisslt, n, m);

                    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 cf = context.AddIntrinsicInt(Intrinsic.X86Comisdge, n, m);
                    Operand zf = context.AddIntrinsicInt(Intrinsic.X86Comisdeq, n, m);
                    Operand nf = context.AddIntrinsicInt(Intrinsic.X86Comisdlt, n, m);

                    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);
                }

                Delegate dlg = op.Size != 0
                    ? (Delegate) new _S32_F64_F64_Bool(SoftFloat64.FPCompare)
                    : (Delegate) new _S32_F32_F32_Bool(SoftFloat32.FPCompare);

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

                EmitSetNzcv(context, nzcv);
            }
        }
Ejemplo n.º 23
0
        public static void Vcvt_FI(ArmEmitterContext context)
        {
            OpCode32SimdCvtFI op = (OpCode32SimdCvtFI)context.CurrOp;

            bool toInteger = (op.Opc2 & 0b100) != 0;

            OperandType floatSize = op.RegisterSize == RegisterSize.Int64 ? OperandType.FP64 : OperandType.FP32;

            if (toInteger)
            {
                bool unsigned       = (op.Opc2 & 1) == 0;
                bool roundWithFpscr = op.Opc != 1;

                Operand toConvert = ExtractScalar(context, floatSize, op.Vm);

                Operand asInteger;

                // TODO: Fast Path.
                if (roundWithFpscr)
                {
                    // These need to get the FPSCR value, so it's worth noting we'd need to do a c# call at some point.
                    if (floatSize == OperandType.FP64)
                    {
                        if (unsigned)
                        {
                            asInteger = context.Call(new _U32_F64(SoftFallback.DoubleToUInt32), toConvert);
                        }
                        else
                        {
                            asInteger = context.Call(new _S32_F64(SoftFallback.DoubleToInt32), toConvert);
                        }
                    }
                    else
                    {
                        if (unsigned)
                        {
                            asInteger = context.Call(new _U32_F32(SoftFallback.FloatToUInt32), toConvert);
                        }
                        else
                        {
                            asInteger = context.Call(new _S32_F32(SoftFallback.FloatToInt32), toConvert);
                        }
                    }
                }
                else
                {
                    // Round towards zero.
                    asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned);
                }

                InsertScalar(context, op.Vd, asInteger);
            }
            else
            {
                bool unsigned = op.Opc == 0;

                Operand toConvert = ExtractScalar(context, OperandType.I32, op.Vm);

                Operand asFloat = EmitFPConvert(context, toConvert, floatSize, !unsigned);

                InsertScalar(context, op.Vd, asFloat);
            }
        }
Ejemplo n.º 24
0
        public static void Fcvt_S(ArmEmitterContext context)
        {
            OpCodeSimd op = (OpCodeSimd)context.CurrOp;

            if (op.Size == 0 && op.Opc == 1) // Single -> Double.
            {
                if (Optimizations.UseSse2)
                {
                    Operand n = GetVec(op.Rn);

                    Operand res = context.AddIntrinsic(Intrinsic.X86Cvtss2sd, context.VectorZero(), n);

                    context.Copy(GetVec(op.Rd), res);
                }
                else
                {
                    Operand ne = context.VectorExtract(OperandType.FP32, GetVec(op.Rn), 0);

                    Operand res = context.ConvertToFP(OperandType.FP64, ne);

                    context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
                }
            }
            else if (op.Size == 1 && op.Opc == 0) // Double -> Single.
            {
                if (Optimizations.UseSse2)
                {
                    Operand n = GetVec(op.Rn);

                    Operand res = context.AddIntrinsic(Intrinsic.X86Cvtsd2ss, context.VectorZero(), n);

                    context.Copy(GetVec(op.Rd), res);
                }
                else
                {
                    Operand ne = context.VectorExtract(OperandType.FP64, GetVec(op.Rn), 0);

                    Operand res = context.ConvertToFP(OperandType.FP32, ne);

                    context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
                }
            }
            else if (op.Size == 0 && op.Opc == 3) // Single -> Half.
            {
                Operand ne = context.VectorExtract(OperandType.FP32, GetVec(op.Rn), 0);

                Delegate dlg = new _U16_F32(SoftFloat32_16.FPConvert);

                Operand res = context.Call(dlg, ne);

                res = context.ZeroExtend16(OperandType.I64, res);

                context.Copy(GetVec(op.Rd), EmitVectorInsert(context, context.VectorZero(), res, 0, 1));
            }
            else if (op.Size == 3 && op.Opc == 0) // Half -> Single.
            {
                Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1);

                Delegate dlg = new _F32_U16(SoftFloat16_32.FPConvert);

                Operand res = context.Call(dlg, ne);

                context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
            }
            else if (op.Size == 1 && op.Opc == 3) // Double -> Half.
            {
                throw new NotImplementedException("Double-precision to half-precision.");
            }
            else if (op.Size == 3 && op.Opc == 1) // Double -> Half.
            {
                throw new NotImplementedException("Half-precision to double-precision.");
            }
            else // Invalid encoding.
            {
                Debug.Assert(false, $"type == {op.Size} && opc == {op.Opc}");
            }
        }
Ejemplo n.º 25
0
        private static void EmitTableBranch(ArmEmitterContext context, Operand guestAddress, bool isJump)
        {
            context.StoreToContext();

            if (guestAddress.Type == OperandType.I32)
            {
                guestAddress = context.ZeroExtend32(OperandType.I64, guestAddress);
            }

            // Store the target guest address into the native context. The stubs uses this address to dispatch into the
            // next translation.
            Operand nativeContext   = context.LoadArgument(OperandType.I64, 0);
            Operand dispAddressAddr = context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset()));

            context.Store(dispAddressAddr, guestAddress);

            Operand hostAddress;

            // If address is mapped onto the function table, we can skip the table walk. Otherwise we fallback
            // onto the dispatch stub.
            if (guestAddress.Kind == OperandKind.Constant && context.FunctionTable.IsValid(guestAddress.Value))
            {
                Operand hostAddressAddr = !context.HasPtc ?
                                          Const(ref context.FunctionTable.GetValue(guestAddress.Value)) :
                                          Const(ref context.FunctionTable.GetValue(guestAddress.Value), new Symbol(SymbolType.FunctionTable, guestAddress.Value));

                hostAddress = context.Load(OperandType.I64, hostAddressAddr);
            }
            else
            {
                hostAddress = !context.HasPtc ?
                              Const((long)context.Stubs.DispatchStub) :
                              Const((long)context.Stubs.DispatchStub, Ptc.DispatchStubSymbol);
            }

            if (isJump)
            {
                context.Tailcall(hostAddress, nativeContext);
            }
            else
            {
                OpCode op = context.CurrOp;

                Operand returnAddress = context.Call(hostAddress, OperandType.I64, nativeContext);

                context.LoadFromContext();

                // Note: The return value of a translated function is always an Int64 with the address execution has
                // returned to. We expect this address to be immediately after the current instruction, if it isn't we
                // keep returning until we reach the dispatcher.
                Operand nextAddr = Const((long)op.Address + op.OpCodeSizeInBytes);

                // Try to continue within this block.
                // If the return address isn't to our next instruction, we need to return so the JIT can figure out
                // what to do.
                Operand lblContinue = context.GetLabel(nextAddr.Value);
                context.BranchIf(lblContinue, returnAddress, nextAddr, Comparison.Equal, BasicBlockFrequency.Cold);

                context.Return(returnAddress);
            }
        }
Ejemplo n.º 26
0
        private static void EmitBranchFallback(ArmEmitterContext context, Operand address, bool isJump)
        {
            Operand fallbackAddr = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), address);

            EmitNativeCall(context, fallbackAddr, isJump);
        }
Ejemplo n.º 27
0
 public static void Clrex(ArmEmitterContext context)
 {
     context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ClearExclusive)));
 }
Ejemplo n.º 28
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);
            }
        }