예제 #1
0
        public static void EmitDataLoadRn(ILEmitterCtx context)
        {
            IOpCodeAlu64 op = (IOpCodeAlu64)context.CurrOp;

            if (op.DataOp == DataOp.Logical || op is IOpCodeAluRs64)
            {
                context.EmitLdintzr(op.Rn);
            }
            else
            {
                context.EmitLdint(op.Rn);
            }
        }
예제 #2
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);
        }
예제 #3
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);
        }
예제 #4
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);
        }
예제 #5
0
        public static void Stp(ILEmitterCtx context)
        {
            OpCodeMemPair64 op = (OpCodeMemPair64)context.CurrOp;

            context.EmitLdarg(TranslatedSub.MemoryArgIdx);

            EmitLoadAddress(context);

            if (op is IOpCodeSimd64)
            {
                context.EmitLdvec(op.Rt);
            }
            else
            {
                context.EmitLdintzr(op.Rt);
            }

            EmitWriteCall(context, op.Size);

            context.EmitLdarg(TranslatedSub.MemoryArgIdx);
            context.EmitLdtmp();
            context.EmitLdc_I8(1 << op.Size);

            context.Emit(OpCodes.Add);

            if (op is IOpCodeSimd64)
            {
                context.EmitLdvec(op.Rt2);
            }
            else
            {
                context.EmitLdintzr(op.Rt2);
            }

            EmitWriteCall(context, op.Size);

            EmitWBackIfNeeded(context);
        }
예제 #6
0
        public static void Blr(ILEmitterCtx context)
        {
            OpCodeBReg64 op = (OpCodeBReg64)context.CurrOp;

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

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

            context.EmitLdtmp();
            context.Emit(OpCodes.Ret);
        }
예제 #7
0
        public static void Movk(ILEmitterCtx context)
        {
            OpCodeMov64 op = (OpCodeMov64)context.CurrOp;

            context.EmitLdintzr(op.Rd);
            context.EmitLdc_I(~(0xffffL << op.Pos));

            context.Emit(OpCodes.And);

            context.EmitLdc_I(op.Imm);

            context.Emit(OpCodes.Or);

            context.EmitStintzr(op.Rd);
        }
예제 #8
0
 public static void EmitAluLoadRm(ILEmitterCtx context)
 {
     if (context.CurrOp is IOpCodeAluRs64 op)
     {
         context.EmitLdintzr(op.Rm);
     }
     else if (context.CurrOp is OpCode32AluRsImm op32)
     {
         InstEmit32Helper.EmitLoadFromRegister(context, op32.Rm);
     }
     else
     {
         throw new InvalidOperationException();
     }
 }
예제 #9
0
        public static void Scvtf_Gp(ILEmitterCtx context)
        {
            OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp;

            context.EmitLdintzr(op.Rn);

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

            EmitFloatCast(context, op.Size);

            EmitScalarSetF(context, op.Rd, op.Size);
        }
예제 #10
0
        private static void EmitMull(ILEmitterCtx context, OpCode addSubOp, bool signed)
        {
            OpCodeMul64 op = (OpCodeMul64)context.CurrOp;

            OpCode castOp = signed
                ? OpCodes.Conv_I8
                : OpCodes.Conv_U8;

            context.EmitLdintzr(op.Ra);
            context.EmitLdintzr(op.Rn);

            context.Emit(OpCodes.Conv_I4);
            context.Emit(castOp);

            context.EmitLdintzr(op.Rm);

            context.Emit(OpCodes.Conv_I4);
            context.Emit(castOp);
            context.Emit(OpCodes.Mul);

            context.Emit(addSubOp);

            context.EmitStintzr(op.Rd);
        }
예제 #11
0
        private static void EmitFallback32_64(ILEmitterCtx context, string name32, string name64)
        {
            OpCodeAlu64 op = (OpCodeAlu64)context.CurrOp;

            context.EmitLdintzr(op.Rn);

            if (op.RegisterSize == RegisterSize.Int32)
            {
                SoftFallback.EmitCall(context, name32);
            }
            else
            {
                SoftFallback.EmitCall(context, name64);
            }

            context.EmitStintzr(op.Rd);
        }
예제 #12
0
        private static void EmitBfmCast(ILEmitterCtx context, OpCode ilOp, bool signed)
        {
            OpCodeBfm64 op = (OpCodeBfm64)context.CurrOp;

            context.EmitLdintzr(op.Rn);

            context.Emit(ilOp);

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

            context.EmitStintzr(op.Rd);
        }
예제 #13
0
        public static void Ucvtf_Gp_Fixed(ILEmitterCtx context)
        {
            OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp;

            context.EmitLdintzr(op.Rn);

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

            context.Emit(OpCodes.Conv_R_Un);

            EmitFloatCast(context, op.Size);

            EmitI2fFBitsMul(context, op.Size, op.FBits);

            EmitScalarSetF(context, op.Rd, op.Size);
        }
예제 #14
0
        public static void Sbfm(ILEmitterCtx context)
        {
            OpCodeBfm64 op = (OpCodeBfm64)context.CurrOp;

            int bitsCount = op.GetBitsCount();

            if (op.Pos + 1 == bitsCount)
            {
                EmitSbfmShift(context);
            }
            else if (op.Pos < op.Shift)
            {
                EmitSbfiz(context);
            }
            else if (op.Pos == 7 && op.Shift == 0)
            {
                EmitSbfmCast(context, OpCodes.Conv_I1);
            }
            else if (op.Pos == 15 && op.Shift == 0)
            {
                EmitSbfmCast(context, OpCodes.Conv_I2);
            }
            else if (op.Pos == 31 && op.Shift == 0)
            {
                EmitSbfmCast(context, OpCodes.Conv_I4);
            }
            else
            {
                EmitBfmLoadRn(context);

                context.EmitLdintzr(op.Rn);

                context.EmitLsl(bitsCount - 1 - op.Pos);
                context.EmitAsr(bitsCount - 1);

                context.EmitLdc_I(~op.TMask);

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

                context.EmitStintzr(op.Rd);
            }
        }
예제 #15
0
        public static void Str(ILEmitterCtx context)
        {
            OpCodeMem64 op = (OpCodeMem64)context.CurrOp;

            EmitLoadAddress(context);

            if (op is IOpCodeSimd64)
            {
                context.EmitLdvec(op.Rt);
            }
            else
            {
                context.EmitLdintzr(op.Rt);
            }

            EmitWriteCall(context, op.Size);

            EmitWBackIfNeeded(context);
        }
예제 #16
0
        public static void Clz(ILEmitterCtx context)
        {
            OpCodeAlu64 op = (OpCodeAlu64)context.CurrOp;

            context.EmitLdintzr(op.Rn);

            if (Lzcnt.IsSupported)
            {
                Type tValue = op.RegisterSize == RegisterSize.Int32 ? typeof(uint) : typeof(ulong);

                context.EmitCall(typeof(Lzcnt).GetMethod(nameof(Lzcnt.LeadingZeroCount), new Type[] { tValue }));
            }
            else
            {
                context.EmitLdc_I4(op.RegisterSize == RegisterSize.Int32 ? 32 : 64);

                SoftFallback.EmitCall(context, nameof(SoftFallback.CountLeadingZeros));
            }

            context.EmitStintzr(op.Rd);
        }
예제 #17
0
        private static void EmitBfiz(ILEmitterCtx context, bool signed)
        {
            OpCodeBfm64 op = (OpCodeBfm64)context.CurrOp;

            int width = op.Pos + 1;

            context.EmitLdintzr(op.Rn);

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

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

            context.EmitStintzr(op.Rd);
        }
예제 #18
0
 public static void EmitAluLoadRn(ILEmitterCtx context)
 {
     if (context.CurrOp is IOpCodeAlu64 op)
     {
         if (op.DataOp == DataOp.Logical || op is IOpCodeAluRs64)
         {
             context.EmitLdintzr(op.Rn);
         }
         else
         {
             context.EmitLdint(op.Rn);
         }
     }
     else if (context.CurrOp is IOpCode32Alu op32)
     {
         InstEmit32Helper.EmitLoadFromRegister(context, op32.Rn);
     }
     else
     {
         throw new InvalidOperationException();
     }
 }
예제 #19
0
 public static void EmitDataLoadRm(ILEmitterCtx context)
 {
     context.EmitLdintzr(((IOpCodeAluRs64)context.CurrOp).Rm);
 }
예제 #20
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);
                }
            }
        }