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); } }
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); }
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); }
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); }
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); }
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); }
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); }
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(); } }
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); }
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); }
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); }
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); }
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); }
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); } }
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); }
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); }
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); }
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(); } }
public static void EmitDataLoadRm(ILEmitterCtx context) { context.EmitLdintzr(((IOpCodeAluRs64)context.CurrOp).Rm); }
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); } } }