예제 #1
0
        private static void EmitReadVector(ILEmitterCtx context, int size)
        {
            EmitAddressCheck(context, size);

            ILLabel lblFastPath = new ILLabel();
            ILLabel lblSlowPath = new ILLabel();
            ILLabel lblEnd      = new ILLabel();

            context.Emit(OpCodes.Brfalse_S, lblFastPath);

            context.MarkLabel(lblSlowPath);

            EmitReadVectorFallback(context, size);

            context.Emit(OpCodes.Br, lblEnd);

            context.MarkLabel(lblFastPath);

            EmitPtPointerLoad(context, lblSlowPath);

            switch (size)
            {
            case 2: context.EmitCall(typeof(Sse), nameof(Sse.LoadScalarVector128));  break;

            case 3:
            {
                Type[] types = new Type[] { typeof(double *) };

                context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.LoadScalarVector128), types));

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

                break;
            }

            case 4: context.EmitCall(typeof(Sse), nameof(Sse.LoadAlignedVector128)); break;

                throw new InvalidOperationException($"Invalid vector load size of {1 << size} bytes.");
            }

            context.MarkLabel(lblEnd);
        }
예제 #2
0
        public static void Bsl_V(ILEmitterCtx context)
        {
            if (Optimizations.UseSse2)
            {
                OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp;

                Type[] typesXorAnd = new Type[] { typeof(Vector128 <byte>), typeof(Vector128 <byte>) };

                context.EmitLdvec(op.Rm);
                context.EmitLdvec(op.Rm);
                context.EmitLdvec(op.Rn);

                context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesXorAnd));

                context.EmitLdvec(op.Rd);

                context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesXorAnd));
                context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesXorAnd));

                context.EmitStvec(op.Rd);

                if (op.RegisterSize == RegisterSize.Simd64)
                {
                    EmitVectorZeroUpper(context, op.Rd);
                }
            }
            else
            {
                EmitVectorTernaryOpZx(context, () =>
                {
                    context.EmitSttmp();
                    context.EmitLdtmp();

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

                    context.EmitLdtmp();

                    context.Emit(OpCodes.Xor);
                });
            }
        }
예제 #3
0
        public static void Blr(ILEmitterCtx context)
        {
            OpCodeBReg64 op = (OpCodeBReg64)context.CurrOp;

            context.EmitLdintzr(op.Rn);
            context.EmitLdc_I(op.Position + 4);
            context.EmitStint(CpuThreadState.LrIndex);
            context.EmitStoreState();

            context.Emit(OpCodes.Ret);
        }
예제 #4
0
 public static void Mvni_V(ILEmitterCtx context)
 {
     if (Optimizations.UseSse2)
     {
         EmitMoviMvni(context, not: true);
     }
     else
     {
         EmitVectorImmUnaryOp(context, () => context.Emit(OpCodes.Not));
     }
 }
예제 #5
0
        public static void Blr(ILEmitterCtx context)
        {
            OpCodeBReg64 op = (OpCodeBReg64)context.CurrOp;

            context.EmitLdintzr(op.Rn);
            context.EmitLdc_I(op.Position + 4);
            context.EmitStint(RegisterAlias.Lr);
            context.EmitStoreState();

            context.Emit(OpCodes.Ret);
        }
예제 #6
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);
        }
예제 #7
0
 public static void Orr_V(ILEmitterCtx context)
 {
     if (Optimizations.UseSse2)
     {
         EmitSse2Op(context, nameof(Sse2.Or));
     }
     else
     {
         EmitVectorBinaryOpZx(context, () => context.Emit(OpCodes.Or));
     }
 }
예제 #8
0
        public static void Shl_S(ILEmitterCtx context)
        {
            OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp;

            EmitScalarUnaryOpZx(context, () =>
            {
                context.EmitLdc_I4(GetImmShl(op));

                context.Emit(OpCodes.Shl);
            });
        }
예제 #9
0
        public static void Bfm(ILEmitterCtx context)
        {
            OpCodeBfm64 op = (OpCodeBfm64)context.CurrOp;

            EmitBfmLoadRn(context);

            context.EmitLdintzr(op.Rd);
            context.EmitLdc_I(~op.WMask & op.TMask);

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

            context.EmitLdintzr(op.Rd);
            context.EmitLdc_I(~op.TMask);

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

            context.EmitStintzr(op.Rd);
        }
예제 #10
0
        public static void Dup_V(ILEmitterCtx context)
        {
            OpCodeSimdIns64 op = (OpCodeSimdIns64)context.CurrOp;

            if (Optimizations.UseSse2)
            {
                Type[] typesSav = new Type[] { UIntTypesPerSizeLog2[op.Size] };

                EmitVectorExtractZx(context, op.Rn, op.DstIndex, op.Size);

                switch (op.Size)
                {
                case 0: context.Emit(OpCodes.Conv_U1); break;

                case 1: context.Emit(OpCodes.Conv_U2); break;

                case 2: context.Emit(OpCodes.Conv_U4); break;
                }

                context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav));

                context.EmitStvec(op.Rd);
            }
            else
            {
                int bytes = op.GetBitsCount() >> 3;
                int elems = bytes >> op.Size;

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

                    EmitVectorInsert(context, op.Rd, index, op.Size);
                }
            }

            if (op.RegisterSize == RegisterSize.Simd64)
            {
                EmitVectorZeroUpper(context, op.Rd);
            }
        }
예제 #11
0
        private static void EmitAluStore(ILEmitterCtx context)
        {
            IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;

            if (op.Rd == RegisterAlias.Aarch32Pc)
            {
                if (op.SetFlags)
                {
                    // TODO: Load SPSR etc.

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

                    ILLabel lblThumb = new ILLabel();
                    ILLabel lblEnd   = new ILLabel();

                    context.Emit(OpCodes.Brtrue_S, lblThumb);

                    context.EmitLdc_I4(~3);

                    context.Emit(OpCodes.Br_S, lblEnd);

                    context.MarkLabel(lblThumb);

                    context.EmitLdc_I4(~1);

                    context.MarkLabel(lblEnd);

                    context.Emit(OpCodes.And);
                    context.Emit(OpCodes.Conv_U8);
                    context.Emit(OpCodes.Ret);
                }
                else
                {
                    EmitAluWritePc(context);
                }
            }
            else
            {
                context.EmitStint(GetRegisterAlias(context.Mode, op.Rd));
            }
        }
예제 #12
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);
            }
        }
예제 #13
0
        private static void EmitBfmLoadRn(ILEmitterCtx context)
        {
            OpCodeBfm64 op = (OpCodeBfm64)context.CurrOp;

            context.EmitLdintzr(op.Rn);

            context.EmitRor(op.Shift);

            context.EmitLdc_I(op.WMask & op.TMask);

            context.Emit(OpCodes.And);
        }
예제 #14
0
        public static void Ands(ILEmitterCtx context)
        {
            EmitAluLoadOpers(context);

            context.Emit(OpCodes.And);

            EmitZeroCvFlags(context);

            context.EmitZnFlagCheck();

            EmitAluStoreS(context);
        }
예제 #15
0
        public static void Adds(ILEmitterCtx context)
        {
            EmitAluLoadOpers(context);

            context.Emit(OpCodes.Add);

            context.EmitZnFlagCheck();

            EmitAddsCCheck(context);
            EmitAddsVCheck(context);
            EmitAluStoreS(context);
        }
예제 #16
0
        private static void EmitAddressCheck(ILEmitterCtx context, int size)
        {
            long addressCheckMask = ~(context.Memory.AddressSpaceSize - 1);

            addressCheckMask |= (1u << size) - 1;

            context.EmitLdint(_tempIntAddress);

            context.EmitLdc_I(addressCheckMask);

            context.Emit(OpCodes.And);
        }
예제 #17
0
        public static void Ucvtf_S(ILEmitterCtx context)
        {
            OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;

            EmitVectorExtractZx(context, op.Rn, 0, op.Size + 2);

            context.Emit(OpCodes.Conv_R_Un);

            EmitFloatCast(context, op.Size);

            EmitScalarSetF(context, op.Rd, op.Size);
        }
예제 #18
0
        private static void EmitReadInt(ILEmitterCtx context, int size)
        {
            EmitAddressCheck(context, size);

            ILLabel lblFastPath = new ILLabel();
            ILLabel lblSlowPath = new ILLabel();
            ILLabel lblEnd      = new ILLabel();

            context.Emit(OpCodes.Brfalse_S, lblFastPath);

            context.MarkLabel(lblSlowPath);

            EmitReadIntFallback(context, size);

            context.Emit(OpCodes.Br, lblEnd);

            context.MarkLabel(lblFastPath);

            EmitPtPointerLoad(context, lblSlowPath);

            switch (size)
            {
            case 0: context.Emit(OpCodes.Ldind_U1); break;

            case 1: context.Emit(OpCodes.Ldind_U2); break;

            case 2: context.Emit(OpCodes.Ldind_U4); break;

            case 3: context.Emit(OpCodes.Ldind_I8); break;
            }

            context.MarkLabel(lblEnd);
        }
예제 #19
0
        private static void EmitExceptionCall(ILEmitterCtx context, string mthdName)
        {
            OpCodeException64 op = (OpCodeException64)context.CurrOp;

            context.EmitStoreState();

            context.EmitLdarg(TranslatedSub.StateArgIdx);

            context.EmitLdc_I8(op.Position);
            context.EmitLdc_I4(op.Id);

            context.EmitPrivateCall(typeof(CpuThreadState), mthdName);

            //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(TranslatedSub.StateArgIdx);

            context.EmitCallPropGet(typeof(CpuThreadState), nameof(CpuThreadState.Running));

            ILLabel lblEnd = new ILLabel();

            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);
            }
        }
예제 #20
0
        public static void Extr(ILEmitterCtx context)
        {
            // TODO: Ensure that the Shift is valid for the Is64Bits.
            OpCodeAluRs64 op = (OpCodeAluRs64)context.CurrOp;

            context.EmitLdintzr(op.Rm);

            if (op.Shift > 0)
            {
                context.EmitLdc_I4(op.Shift);

                context.Emit(OpCodes.Shr_Un);

                context.EmitLdintzr(op.Rn);
                context.EmitLdc_I4(op.GetBitsCount() - op.Shift);

                context.Emit(OpCodes.Shl);
                context.Emit(OpCodes.Or);
            }

            EmitAluStore(context);
        }
예제 #21
0
        private static void EmitCrc32(ILEmitterCtx context, string name)
        {
            OpCodeAluRs64 op = (OpCodeAluRs64)context.CurrOp;

            context.EmitLdintzr(op.Rn);

            if (op.RegisterSize != RegisterSize.Int32)
            {
                context.Emit(OpCodes.Conv_U4);
            }

            context.EmitLdintzr(op.Rm);

            SoftFallback.EmitCall(context, name);

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

            context.EmitStintzr(op.Rd);
        }
예제 #22
0
        private static void EmitTb(ILEmitterCtx context, OpCode ilOp)
        {
            OpCodeBImmTest64 op = (OpCodeBImmTest64)context.CurrOp;

            context.EmitLdintzr(op.Rt);
            context.EmitLdc_I(1L << op.Pos);

            context.Emit(OpCodes.And);

            context.EmitLdc_I(0);

            EmitBranch(context, ilOp);
        }
예제 #23
0
        private static void EmitBfmShift(ILEmitterCtx context, bool signed)
        {
            OpCodeBfm64 op = (OpCodeBfm64)context.CurrOp;

            context.EmitLdintzr(op.Rn);
            context.EmitLdc_I4(op.Shift);

            context.Emit(signed
                ? OpCodes.Shr
                : OpCodes.Shr_Un);

            context.EmitStintzr(op.Rd);
        }
예제 #24
0
        private static void EmitCmtstOp(ILEmitterCtx context, bool scalar)
        {
            OpCodeSimdReg64 op = (OpCodeSimdReg64)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++)
            {
                EmitVectorExtractZx(context, op.Rn, index, op.Size);
                EmitVectorExtractZx(context, op.Rm, index, op.Size);

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

                context.Emit(OpCodes.And);

                context.EmitLdc_I8(0L);

                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 == RegisterSize.Simd64) || scalar)
            {
                EmitVectorZeroUpper(context, op.Rd);
            }
        }
예제 #25
0
        public static void Rshrn_V(ILEmitterCtx context)
        {
            if (Optimizations.UseSsse3)
            {
                OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp;

                Type[] typesAdd = new Type[] { VectorUIntTypesPerSizeLog2[op.Size + 1], VectorUIntTypesPerSizeLog2[op.Size + 1] };
                Type[] typesSrl = new Type[] { VectorUIntTypesPerSizeLog2[op.Size + 1], typeof(byte) };
                Type[] typesSfl = new Type[] { typeof(Vector128 <sbyte>), typeof(Vector128 <sbyte>) };
                Type[] typesSav = new Type[] { UIntTypesPerSizeLog2[op.Size + 1] };
                Type[] typesSve = new Type[] { typeof(long), typeof(long) };

                string nameMov = op.RegisterSize == RegisterSize.Simd128
                    ? nameof(Sse.MoveLowToHigh)
                    : nameof(Sse.MoveHighToLow);

                int shift = GetImmShr(op);

                long roundConst = 1L << (shift - 1);

                context.EmitLdvec(op.Rd);
                VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero));

                context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveLowToHigh)));

                context.EmitLdvec(op.Rn);

                context.EmitLdc_I8(roundConst);
                context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav));

                context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd));

                context.EmitLdc_I4(shift);
                context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesSrl)); // value

                context.EmitLdc_I8(_masks_RshrnShrn[op.Size]);                                      // mask
                context.Emit(OpCodes.Dup);                                                          // mask

                context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSve));

                context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), typesSfl));

                context.EmitCall(typeof(Sse).GetMethod(nameMov));

                context.EmitStvec(op.Rd);
            }
            else
            {
                EmitVectorShrImmNarrowOpZx(context, round: true);
            }
        }
예제 #26
0
        public static void Ushll_V(ILEmitterCtx context)
        {
            OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp;

            int shift = GetImmShl(op);

            if (Optimizations.UseSse41)
            {
                Type[] typesSll = new Type[] { VectorUIntTypesPerSizeLog2[op.Size + 1], typeof(byte) };
                Type[] typesCvt = new Type[] { VectorUIntTypesPerSizeLog2[op.Size] };

                string[] namesCvt = new string[] { nameof(Sse41.ConvertToVector128Int16),
                                                   nameof(Sse41.ConvertToVector128Int32),
                                                   nameof(Sse41.ConvertToVector128Int64) };

                context.EmitLdvec(op.Rn);

                if (op.RegisterSize == RegisterSize.Simd128)
                {
                    context.Emit(OpCodes.Ldc_I4_8);
                    context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSll));
                }

                context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt));

                if (shift != 0)
                {
                    context.EmitLdc_I4(shift);
                    context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesSll));
                }

                context.EmitStvec(op.Rd);
            }
            else
            {
                EmitVectorShImmWidenBinaryZx(context, () => context.Emit(OpCodes.Shl), shift);
            }
        }
예제 #27
0
        public static void Adds(ILEmitterCtx context)
        {
            context.TryOptMarkCondWithoutCmp();

            EmitAluLoadOpers(context);

            context.Emit(OpCodes.Add);

            context.EmitZnFlagCheck();

            EmitAddsCCheck(context);
            EmitAddsVCheck(context);
            EmitAluStoreS(context);
        }
예제 #28
0
        public static void Subs(ILEmitterCtx context)
        {
            context.TryOptMarkCondWithoutCmp();

            EmitDataLoadOpers(context);

            context.Emit(OpCodes.Sub);

            context.EmitZnFlagCheck();

            EmitSubsCCheck(context);
            EmitSubsVCheck(context);
            EmitDataStoreS(context);
        }
예제 #29
0
        private static void EmitDiv(ILEmitterCtx context, OpCode ilOp)
        {
            // If Rm == 0, Rd = 0 (division by zero).
            context.EmitLdc_I(0);

            EmitAluLoadRm(context);

            context.EmitLdc_I(0);

            ILLabel badDiv = new ILLabel();

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

                EmitAluLoadRn(context);

                context.EmitLdc_I(intMin);

                context.Emit(OpCodes.Ceq);

                EmitAluLoadRm(context);

                context.EmitLdc_I(-1);

                context.Emit(OpCodes.Ceq);
                context.Emit(OpCodes.And);
                context.Emit(OpCodes.Brtrue_S, badDiv);
                context.Emit(OpCodes.Pop);
            }

            EmitAluLoadRn(context);
            EmitAluLoadRm(context);

            context.Emit(ilOp);

            context.MarkLabel(badDiv);

            EmitAluStore(context);
        }
예제 #30
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);
            }
        }