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); }
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); }); } }
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); }
public static void Mvni_V(ILEmitterCtx context) { if (Optimizations.UseSse2) { EmitMoviMvni(context, not: true); } else { EmitVectorImmUnaryOp(context, () => context.Emit(OpCodes.Not)); } }
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); }
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); }
public static void Orr_V(ILEmitterCtx context) { if (Optimizations.UseSse2) { EmitSse2Op(context, nameof(Sse2.Or)); } else { EmitVectorBinaryOpZx(context, () => context.Emit(OpCodes.Or)); } }
public static void Shl_S(ILEmitterCtx context) { OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; EmitScalarUnaryOpZx(context, () => { context.EmitLdc_I4(GetImmShl(op)); context.Emit(OpCodes.Shl); }); }
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); }
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); } }
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)); } }
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); } }
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); }
public static void Ands(ILEmitterCtx context) { EmitAluLoadOpers(context); context.Emit(OpCodes.And); EmitZeroCvFlags(context); context.EmitZnFlagCheck(); EmitAluStoreS(context); }
public static void Adds(ILEmitterCtx context) { EmitAluLoadOpers(context); context.Emit(OpCodes.Add); context.EmitZnFlagCheck(); EmitAddsCCheck(context); EmitAddsVCheck(context); EmitAluStoreS(context); }
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); }
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); }
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); }
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); } }
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 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); }
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); }
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); }
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); } }
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); } }
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); } }
public static void Adds(ILEmitterCtx context) { context.TryOptMarkCondWithoutCmp(); EmitAluLoadOpers(context); context.Emit(OpCodes.Add); context.EmitZnFlagCheck(); EmitAddsCCheck(context); EmitAddsVCheck(context); EmitAluStoreS(context); }
public static void Subs(ILEmitterCtx context) { context.TryOptMarkCondWithoutCmp(); EmitDataLoadOpers(context); context.Emit(OpCodes.Sub); context.EmitZnFlagCheck(); EmitSubsCCheck(context); EmitSubsVCheck(context); EmitDataStoreS(context); }
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); }
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); } }