Esempio n. 1
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);
        }
Esempio n. 2
0
        private static void EmitCsel(ILEmitterCtx context, CselOperation cselOp)
        {
            OpCodeCsel64 op = (OpCodeCsel64)context.CurrOp;

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

            context.EmitCondBranch(lblTrue, op.Cond);
            context.EmitLdintzr(op.Rm);

            if (cselOp == CselOperation.Increment)
            {
                context.EmitLdc_I(1);

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

            context.Emit(OpCodes.Br_S, lblEnd);

            context.MarkLabel(lblTrue);

            context.EmitLdintzr(op.Rn);

            context.MarkLabel(lblEnd);

            context.EmitStintzr(op.Rd);
        }
Esempio n. 3
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);
        }
Esempio n. 4
0
        private static void EmitWriteVector(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);

            EmitWriteVectorFallback(context, size);

            context.Emit(OpCodes.Br, lblEnd);

            context.MarkLabel(lblFastPath);

            EmitPtPointerLoad(context, lblSlowPath);

            context.EmitLdvec(_tempVecValue);

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

            case 3: context.EmitCall(typeof(Sse2), nameof(Sse2.StoreScalar)); break;

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

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

            context.MarkLabel(lblEnd);
        }
Esempio n. 5
0
        private static void EmitStore(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);
            }

            ILLabel lblEx  = new ILLabel();
            ILLabel lblEnd = new ILLabel();

            if (exclusive)
            {
                EmitMemoryCall(context, nameof(MemoryManager.TestExclusive), op.Rn);

                context.Emit(OpCodes.Brtrue_S, lblEx);

                context.EmitLdc_I8(1);
                context.EmitStintzr(op.Rs);

                context.Emit(OpCodes.Br_S, lblEnd);
            }

            context.MarkLabel(lblEx);

            context.EmitLdarg(TranslatedSub.MemoryArgIdx);
            context.EmitLdint(op.Rn);
            context.EmitLdintzr(op.Rt);

            EmitWriteCall(context, op.Size);

            if (pair)
            {
                context.EmitLdarg(TranslatedSub.MemoryArgIdx);
                context.EmitLdint(op.Rn);
                context.EmitLdc_I8(1 << op.Size);

                context.Emit(OpCodes.Add);

                context.EmitLdintzr(op.Rt2);

                EmitWriteCall(context, op.Size);
            }

            if (exclusive)
            {
                context.EmitLdc_I8(0);
                context.EmitStintzr(op.Rs);

                EmitMemoryCall(context, nameof(MemoryManager.ClearExclusiveForStore));
            }

            context.MarkLabel(lblEnd);
        }
Esempio n. 6
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);
        }
Esempio n. 7
0
        private static void EmitFcmp(ILEmitterCtx context, OpCode ilOp, int index, bool scalar)
        {
            OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;

            int sizeF = op.Size & 1;

            ulong szMask = ulong.MaxValue >> (64 - (32 << sizeF));

            EmitVectorExtractF(context, op.Rn, index, sizeF);

            if (op is OpCodeSimdReg64 binOp)
            {
                EmitVectorExtractF(context, binOp.Rm, index, sizeF);
            }
            else if (sizeF == 0)
            {
                context.EmitLdc_R4(0f);
            }
            else /* if (SizeF == 1) */
            {
                context.EmitLdc_R8(0d);
            }

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

            context.Emit(ilOp, lblTrue);

            if (scalar)
            {
                EmitVectorZeroAll(context, op.Rd);
            }
            else
            {
                EmitVectorInsert(context, op.Rd, index, sizeF + 2, 0);
            }

            context.Emit(OpCodes.Br_S, lblEnd);

            context.MarkLabel(lblTrue);

            if (scalar)
            {
                EmitVectorInsert(context, op.Rd, index, 3, (long)szMask);

                EmitVectorZeroUpper(context, op.Rd);
            }
            else
            {
                EmitVectorInsert(context, op.Rd, index, sizeF + 2, (long)szMask);
            }

            context.MarkLabel(lblEnd);
        }
Esempio n. 8
0
        private static void EmitContinueOrReturnCheck(ILEmitterCtx context)
        {
            // Note: The return value of the called method will be placed
            // at the Stack, the return value is always a Int64 with the
            // return address of the function. We check if the address is
            // correct, if it isn't we keep returning until we reach the dispatcher.
            if (context.CurrBlock.Next != null)
            {
                context.Emit(OpCodes.Dup);

                context.EmitLdc_I8(context.CurrOp.Position + 4);

                ILLabel lblContinue = new ILLabel();

                context.Emit(OpCodes.Beq_S, lblContinue);
                context.Emit(OpCodes.Ret);

                context.MarkLabel(lblContinue);

                context.Emit(OpCodes.Pop);

                context.EmitLoadContext();
            }
            else
            {
                context.Emit(OpCodes.Ret);
            }
        }
Esempio n. 9
0
        private static void EmitBranch(ILEmitterCtx context, Condition cond)
        {
            OpCodeBImm64 op = (OpCodeBImm64)context.CurrOp;

            if (context.CurrBlock.Branch != null)
            {
                context.EmitCondBranch(context.GetLabel(op.Imm), cond);

                if (context.CurrBlock.Next == null)
                {
                    context.EmitStoreContext();
                    context.EmitLdc_I8(op.Position + 4);

                    context.Emit(OpCodes.Ret);
                }
            }
            else
            {
                context.EmitStoreContext();

                ILLabel lblTaken = new ILLabel();

                context.EmitCondBranch(lblTaken, cond);

                context.EmitLdc_I8(op.Position + 4);

                context.Emit(OpCodes.Ret);

                context.MarkLabel(lblTaken);

                context.EmitLdc_I8(op.Imm);

                context.Emit(OpCodes.Ret);
            }
        }
Esempio n. 10
0
        public static void EmitCall(ILEmitterCtx context, long imm)
        {
            if (context.TryOptEmitSubroutineCall())
            {
                //Note: the return value of the called method will be placed
                //at the Stack, the return value is always a Int64 with the
                //return address of the function. We check if the address is
                //correct, if it isn't we keep returning until we reach the dispatcher.
                context.Emit(OpCodes.Dup);

                context.EmitLdc_I8(context.CurrOp.Position + 4);

                ILLabel lblContinue = new ILLabel();

                context.Emit(OpCodes.Beq_S, lblContinue);
                context.Emit(OpCodes.Ret);

                context.MarkLabel(lblContinue);

                context.Emit(OpCodes.Pop);

                context.EmitLoadState();
            }
            else
            {
                context.EmitLdc_I8(imm);

                context.Emit(OpCodes.Ret);
            }
        }
Esempio n. 11
0
        private static void EmitBranch(ILEmitterCtx context, OpCode ilOp)
        {
            OpCodeBImm64 op = (OpCodeBImm64)context.CurrOp;

            if (context.CurrBlock.Next != null &&
                context.CurrBlock.Branch != null)
            {
                context.Emit(ilOp, context.GetLabel(op.Imm));
            }
            else
            {
                context.EmitStoreState();

                ILLabel lblTaken = new ILLabel();

                context.Emit(ilOp, lblTaken);

                context.EmitLdc_I8(op.Position + 4);

                context.Emit(OpCodes.Ret);

                context.MarkLabel(lblTaken);

                context.EmitLdc_I8(op.Imm);

                context.Emit(OpCodes.Ret);
            }
        }
Esempio n. 12
0
        public static void Fccmp_S(ILEmitterCtx context)
        {
            OpCodeSimdFcond64 op = (OpCodeSimdFcond64)context.CurrOp;

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

            context.EmitCondBranch(lblTrue, op.Cond);

            EmitSetNzcv(context, op.Nzcv);

            context.Emit(OpCodes.Br, lblEnd);

            context.MarkLabel(lblTrue);

            Fcmp_S(context);

            context.MarkLabel(lblEnd);
        }
Esempio n. 13
0
        private static void EmitCmpOp(ILEmitterCtx context, OpCode ilOp, bool scalar)
        {
            OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;

            int bytes = op.GetBitsCount() >> 3;
            int elems = !scalar ? bytes >> op.Size : 1;

            ulong szMask = ulong.MaxValue >> (64 - (8 << op.Size));

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

                if (op is OpCodeSimdReg64 binOp)
                {
                    EmitVectorExtractSx(context, binOp.Rm, index, op.Size);
                }
                else
                {
                    context.EmitLdc_I8(0L);
                }

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

                context.Emit(ilOp, lblTrue);

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

                context.Emit(OpCodes.Br_S, lblEnd);

                context.MarkLabel(lblTrue);

                EmitVectorInsert(context, op.Rd, index, op.Size, (long)szMask);

                context.MarkLabel(lblEnd);
            }

            if ((op.RegisterSize == RegisterSize.Simd64) || scalar)
            {
                EmitVectorZeroUpper(context, op.Rd);
            }
        }
Esempio n. 14
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);
        }
Esempio n. 15
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));
            }
        }
Esempio n. 16
0
        public static void Fcsel_S(ILEmitterCtx context)
        {
            OpCodeSimdFcond64 op = (OpCodeSimdFcond64)context.CurrOp;

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

            context.EmitCondBranch(lblTrue, op.Cond);

            EmitVectorExtractF(context, op.Rm, 0, op.Size);

            context.Emit(OpCodes.Br_S, lblEnd);

            context.MarkLabel(lblTrue);

            EmitVectorExtractF(context, op.Rn, 0, op.Size);

            context.MarkLabel(lblEnd);

            EmitScalarSetF(context, op.Rd, op.Size);
        }
Esempio n. 17
0
        private static void EmitWriteInt(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);

            EmitWriteIntFallback(context, size);

            context.Emit(OpCodes.Br, lblEnd);

            context.MarkLabel(lblFastPath);

            EmitPtPointerLoad(context, lblSlowPath);

            context.EmitLdint(_tempIntValue);

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

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

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

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

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

            context.MarkLabel(lblEnd);
        }
Esempio n. 18
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);
        }
Esempio n. 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);
            }
        }
Esempio n. 20
0
        public static void Bl(ILEmitterCtx context)
        {
            OpCodeBImmAl64 op = (OpCodeBImmAl64)context.CurrOp;

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

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

                context.EmitLdc_I8(op.Position + 4);

                ILLabel lblContinue = new ILLabel();

                context.Emit(OpCodes.Beq_S, lblContinue);
                context.Emit(OpCodes.Ret);

                context.MarkLabel(lblContinue);

                context.Emit(OpCodes.Pop);

                context.EmitLoadState(context.CurrBlock.Next);
            }
            else
            {
                context.EmitLdc_I8(op.Imm);

                context.Emit(OpCodes.Ret);
            }
        }
Esempio n. 21
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);
        }
Esempio n. 22
0
        private static void EmitVectorShl(ILEmitterCtx context, bool signed)
        {
            //This instruction shifts the value on vector A by the number of bits
            //specified on the signed, lower 8 bits of vector B. If the shift value
            //is greater or equal to the data size of each lane, then the result is zero.
            //Additionally, negative shifts produces right shifts by the negated shift value.
            OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;

            int maxShift = 8 << op.Size;

            Action emit = () =>
            {
                ILLabel lblShl  = new ILLabel();
                ILLabel lblZero = new ILLabel();
                ILLabel lblEnd  = new ILLabel();

                void EmitShift(OpCode ilOp)
                {
                    context.Emit(OpCodes.Dup);

                    context.EmitLdc_I4(maxShift);

                    context.Emit(OpCodes.Bge_S, lblZero);
                    context.Emit(ilOp);
                    context.Emit(OpCodes.Br_S, lblEnd);
                }

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

                context.EmitLdc_I4(0);

                context.Emit(OpCodes.Bge_S, lblShl);
                context.Emit(OpCodes.Neg);

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

                context.MarkLabel(lblShl);

                EmitShift(OpCodes.Shl);

                context.MarkLabel(lblZero);

                context.Emit(OpCodes.Pop);
                context.Emit(OpCodes.Pop);

                context.EmitLdc_I8(0);

                context.MarkLabel(lblEnd);
            };

            if (signed)
            {
                EmitVectorBinaryOpSx(context, emit);
            }
            else
            {
                EmitVectorBinaryOpZx(context, emit);
            }
        }
Esempio n. 23
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);
            }
        }
Esempio n. 24
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);
            }
        }
Esempio n. 25
0
        private static void EmitStore(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);
            }

            if (exclusive)
            {
                ILLabel lblEx  = new ILLabel();
                ILLabel lblEnd = new ILLabel();

                context.EmitLdarg(TranslatedSub.StateArgIdx);
                context.EmitLdint(op.Rn);

                context.EmitPrivateCall(typeof(CpuThreadState), nameof(CpuThreadState.CheckExclusiveAddress));

                context.Emit(OpCodes.Brtrue_S, lblEx);

                //Address check failed, set error right away and do not store anything.
                context.EmitLdc_I4(1);
                context.EmitStintzr(op.Rs);

                context.Emit(OpCodes.Br, lblEnd);

                //Address check passsed.
                context.MarkLabel(lblEx);

                context.EmitLdarg(TranslatedSub.MemoryArgIdx);
                context.EmitLdint(op.Rn);

                context.EmitLdarg(TranslatedSub.StateArgIdx);

                context.EmitCallPrivatePropGet(typeof(CpuThreadState), nameof(CpuThreadState.ExclusiveValueLow));

                void EmitCast()
                {
                    //The input should be always int64.
                    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;
                    }
                }

                EmitCast();

                if (pair)
                {
                    context.EmitLdarg(TranslatedSub.StateArgIdx);

                    context.EmitCallPrivatePropGet(typeof(CpuThreadState), nameof(CpuThreadState.ExclusiveValueHigh));

                    EmitCast();

                    context.EmitLdintzr(op.Rt);

                    EmitCast();

                    context.EmitLdintzr(op.Rt2);

                    EmitCast();

                    switch (op.Size)
                    {
                    case 2: context.EmitPrivateCall(typeof(MemoryManager), nameof(MemoryManager.AtomicCompareExchange2xInt32)); break;

                    case 3: context.EmitPrivateCall(typeof(MemoryManager), nameof(MemoryManager.AtomicCompareExchangeInt128));  break;

                    default: throw new InvalidOperationException($"Invalid store size of {1 << op.Size} bytes.");
                    }
                }
                else
                {
                    context.EmitLdintzr(op.Rt);

                    EmitCast();

                    switch (op.Size)
                    {
                    case 0: context.EmitCall(typeof(MemoryManager), nameof(MemoryManager.AtomicCompareExchangeByte));  break;

                    case 1: context.EmitCall(typeof(MemoryManager), nameof(MemoryManager.AtomicCompareExchangeInt16)); break;

                    case 2: context.EmitCall(typeof(MemoryManager), nameof(MemoryManager.AtomicCompareExchangeInt32)); break;

                    case 3: context.EmitCall(typeof(MemoryManager), nameof(MemoryManager.AtomicCompareExchangeInt64)); break;

                    default: throw new InvalidOperationException($"Invalid store size of {1 << op.Size} bytes.");
                    }
                }

                //The value returned is a bool, true if the values compared
                //were equal and the new value was written, false otherwise.
                //We need to invert this result, as on ARM 1 indicates failure,
                //and 0 success on those instructions.
                context.EmitLdc_I4(1);

                context.Emit(OpCodes.Xor);
                context.Emit(OpCodes.Dup);
                context.Emit(OpCodes.Conv_U8);

                context.EmitStintzr(op.Rs);

                //Only clear the exclusive monitor if the store was successful (Rs = false).
                context.Emit(OpCodes.Brtrue_S, lblEnd);

                Clrex(context);

                context.MarkLabel(lblEnd);
            }
            else
            {
                void EmitWrite(int rt, long offset)
                {
                    context.EmitLdarg(TranslatedSub.MemoryArgIdx);
                    context.EmitLdint(op.Rn);

                    if (offset != 0)
                    {
                        context.EmitLdc_I8(offset);

                        context.Emit(OpCodes.Add);
                    }

                    context.EmitLdintzr(rt);

                    EmitWriteCall(context, op.Size);
                }

                EmitWrite(op.Rt, 0);

                if (pair)
                {
                    EmitWrite(op.Rt2, 1 << op.Size);
                }
            }
        }