private static void EmitBranch(ILEmitterCtx context, Cond cond) { OpCodeBImm64 op = (OpCodeBImm64)context.CurrOp; if (context.CurrBlock.Next != null && context.CurrBlock.Branch != null) { context.EmitCondBranch(context.GetLabel(op.Imm), cond); } else { context.EmitStoreState(); 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); } }
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); } }
public static void Rev16_V(ILEmitterCtx context) { if (Optimizations.UseSsse3) { OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; Type[] typesSve = new Type[] { typeof(long), typeof(long) }; Type[] typesSfl = new Type[] { typeof(Vector128 <sbyte>), typeof(Vector128 <sbyte>) }; context.EmitLdvec(op.Rn); // value context.EmitLdc_I8(14L << 56 | 15L << 48 | 12L << 40 | 13L << 32 | 10L << 24 | 11L << 16 | 08L << 8 | 09L << 0); // maskE1 context.EmitLdc_I8(06L << 56 | 07L << 48 | 04L << 40 | 05L << 32 | 02L << 24 | 03L << 16 | 00L << 8 | 01L << 0); // maskE0 context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSve)); context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), typesSfl)); context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { EmitVectorZeroUpper(context, op.Rd); } } else { EmitRev_V(context, containerSize: 1); } }
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); }
private static void EmitSimdMemMs(ILEmitterCtx context, bool isLoad) { OpCodeSimdMemMs64 op = (OpCodeSimdMemMs64)context.CurrOp; int offset = 0; for (int rep = 0; rep < op.Reps; rep++) { for (int elem = 0; elem < op.Elems; elem++) { for (int sElem = 0; sElem < op.SElems; sElem++) { int rtt = (op.Rt + rep + sElem) & 0x1f; if (isLoad) { context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitLdint(op.Rn); context.EmitLdc_I8(offset); context.Emit(OpCodes.Add); EmitReadZxCall(context, op.Size); EmitVectorInsert(context, rtt, elem, op.Size); if (op.RegisterSize == RegisterSize.Simd64 && elem == op.Elems - 1) { EmitVectorZeroUpper(context, rtt); } } else { context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitLdint(op.Rn); context.EmitLdc_I8(offset); context.Emit(OpCodes.Add); EmitVectorExtractZx(context, rtt, elem, op.Size); EmitWriteCall(context, op.Size); } offset += 1 << op.Size; } } } if (op.WBack) { EmitSimdMemWBack(context, offset); } }
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 Stp(ILEmitterCtx context) { OpCodeMemPair64 op = (OpCodeMemPair64)context.CurrOp; EmitLoadAddress(context); if (op is IOpCodeSimd64) { context.EmitLdvec(op.Rt); } else { context.EmitLdintzr(op.Rt); } EmitWriteCall(context, op.Size); 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 Orn_V(ILEmitterCtx context) { if (Optimizations.UseSse2) { OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; Type[] typesSav = new Type[] { typeof(long) }; Type[] typesAntOr = new Type[] { typeof(Vector128 <long>), typeof(Vector128 <long>) }; context.EmitLdvec(op.Rn); context.EmitLdvec(op.Rm); context.EmitLdc_I8(-1L); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAntOr)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesAntOr)); context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { EmitVectorZeroUpper(context, op.Rd); } } else { EmitVectorBinaryOpZx(context, () => { context.Emit(OpCodes.Not); context.Emit(OpCodes.Or); }); } }
public static void Sli_V(ILEmitterCtx context) { OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; int bytes = op.GetBitsCount() >> 3; int elems = bytes >> op.Size; int shift = GetImmShl(op); ulong mask = shift != 0 ? ulong.MaxValue >> (64 - shift) : 0; for (int index = 0; index < elems; index++) { EmitVectorExtractZx(context, op.Rn, index, op.Size); context.EmitLdc_I4(shift); context.Emit(OpCodes.Shl); EmitVectorExtractZx(context, op.Rd, index, op.Size); context.EmitLdc_I8((long)mask); context.Emit(OpCodes.And); context.Emit(OpCodes.Or); EmitVectorInsert(context, op.Rd, index, op.Size); } if (op.RegisterSize == RegisterSize.Simd64) { EmitVectorZeroUpper(context, op.Rd); } }
private static void EmitMoviMvni(ILEmitterCtx context, bool not) { OpCodeSimdImm64 op = (OpCodeSimdImm64)context.CurrOp; Type[] typesSav = new Type[] { UIntTypesPerSizeLog2[op.Size] }; long imm = op.Imm; if (not) { imm = ~imm; } if (op.Size < 3) { context.EmitLdc_I4((int)imm); } else { context.EmitLdc_I8(imm); } context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { EmitVectorZeroUpper(context, op.Rd); } }
public static void Ldr_Literal(ILEmitterCtx context) { IOpCodeLit64 op = (IOpCodeLit64)context.CurrOp; if (op.Prefetch) { return; } context.EmitLdc_I8(op.Imm); if (op.Signed) { EmitReadSx64Call(context, op.Size); } else { EmitReadZxCall(context, op.Size); } if (op is IOpCodeSimd64) { context.EmitStvec(op.Rt); } else { context.EmitStint(op.Rt); } }
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); } }
public static void Sys(ILEmitterCtx context) { //This instruction is used to do some operations on the CPU like cache invalidation, //address translation and the like. //We treat it as no-op here since we don't have any cache being emulated anyway. OpCodeSystem64 op = (OpCodeSystem64)context.CurrOp; switch (GetPackedId(op)) { case 0b11_011_0111_0100_001: { //DC ZVA for (int offs = 0; offs < (4 << CpuThreadState.DczSizeLog2); offs += 8) { context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitLdintzr(op.Rt); context.EmitLdc_I(offs); context.Emit(OpCodes.Add); context.EmitLdc_I8(0); InstEmitMemoryHelper.EmitWriteCall(context, 3); } break; } //No-op case 0b11_011_0111_1110_001: //DC CIVAC break; } }
public static void EmitVectorImmOp(ILEmitterCtx context, Action emit, bool binary) { OpCodeSimdImm64 op = (OpCodeSimdImm64)context.CurrOp; int bytes = op.GetBitsCount() >> 3; int elems = bytes >> op.Size; for (int index = 0; index < elems; index++) { if (binary) { EmitVectorExtractZx(context, op.Rd, index, op.Size); } context.EmitLdc_I8(op.Imm); emit(); EmitVectorInsert(context, op.Rd, index, op.Size); } if (op.RegisterSize == RegisterSize.Simd64) { EmitVectorZeroUpper(context, op.Rd); } }
public static void Cmle_V(ILEmitterCtx context) { if (Optimizations.UseSse42) { OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; Type[] typesAnt = new Type[] { typeof(Vector128 <long>), typeof(Vector128 <long>) }; Type[] typesSav = new Type[] { typeof(long) }; Type typeSse = op.Size != 3 ? typeof(Sse2) : typeof(Sse42); context.EmitLdvec(op.Rn); VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); context.EmitCall(typeSse.GetMethod(nameof(Sse2.CompareGreaterThan), typesCmp)); context.EmitLdc_I8(-1L); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAnt)); context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { EmitVectorZeroUpper(context, op.Rd); } } else { EmitCmpOp(context, OpCodes.Ble_S, scalar: false); } }
public static void Fmov_Si(ILEmitterCtx context) { OpCodeSimdFmov64 op = (OpCodeSimdFmov64)context.CurrOp; context.EmitLdc_I8(op.Imm); EmitScalarSet(context, op.Rd, op.Size + 2); }
public static void Xtn_V(ILEmitterCtx context) { OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; if (Optimizations.UseSsse3) { Type[] typesSve = new Type[] { typeof(long), typeof(long) }; string nameMov = op.RegisterSize == RegisterSize.Simd128 ? nameof(Sse.MoveLowToHigh) : nameof(Sse.MoveHighToLow); context.EmitLdvec(op.Rd); VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveLowToHigh))); context.EmitLdvec(op.Rn); // value context.EmitLdc_I8(_masksE0_TrnUzpXtn[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), GetTypesSflUpk(0))); context.EmitCall(typeof(Sse).GetMethod(nameMov)); context.EmitStvec(op.Rd); } else { int elems = 8 >> op.Size; int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0; if (part != 0) { context.EmitLdvec(op.Rd); context.EmitStvectmp(); } for (int index = 0; index < elems; index++) { EmitVectorExtractZx(context, op.Rn, index, op.Size + 1); EmitVectorInsertTmp(context, part + index, op.Size); } context.EmitLdvectmp(); context.EmitStvec(op.Rd); if (part == 0) { EmitVectorZeroUpper(context, op.Rd); } } }
// dst64 = (Int(src64, signed) + roundConst) >> shift; private static void EmitShrImm64(ILEmitterCtx context, bool signed, long roundConst, int shift) { context.EmitLdc_I8(roundConst); context.EmitLdc_I4(shift); SoftFallback.EmitCall(context, signed ? nameof(SoftFallback.SignedShrImm64) : nameof(SoftFallback.UnsignedShrImm64)); }
private static void EmitShrImmOp(ILEmitterCtx context, ShrImmFlags flags) { OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; bool scalar = (flags & ShrImmFlags.Scalar) != 0; bool signed = (flags & ShrImmFlags.Signed) != 0; bool round = (flags & ShrImmFlags.Round) != 0; bool accumulate = (flags & ShrImmFlags.Accumulate) != 0; int shift = GetImmShr(op); long roundConst = 1L << (shift - 1); int bytes = op.GetBitsCount() >> 3; int elems = !scalar ? bytes >> op.Size : 1; for (int index = 0; index < elems; index++) { EmitVectorExtract(context, op.Rn, index, op.Size, signed); if (op.Size <= 2) { if (round) { context.EmitLdc_I8(roundConst); context.Emit(OpCodes.Add); } context.EmitLdc_I4(shift); context.Emit(signed ? OpCodes.Shr : OpCodes.Shr_Un); } else /* if (op.Size == 3) */ { EmitShrImm64(context, signed, round ? roundConst : 0L, shift); } if (accumulate) { EmitVectorExtract(context, op.Rd, index, op.Size, signed); context.Emit(OpCodes.Add); } EmitVectorInsertTmp(context, index, op.Size); } context.EmitLdvectmp(); context.EmitStvec(op.Rd); if ((op.RegisterSize == RegisterSize.Simd64) || scalar) { EmitVectorZeroUpper(context, op.Rd); } }
public static void EmitCall(ILEmitterCtx context, long imm) { if (context.Tier == TranslationTier.Tier0) { context.EmitStoreContext(); context.TranslateAhead(imm); context.EmitLdc_I8(imm); context.Emit(OpCodes.Ret); return; } if (!context.TryOptEmitSubroutineCall()) { context.HasSlowCall = true; context.EmitStoreContext(); context.TranslateAhead(imm); context.EmitLdarg(TranslatedSub.StateArgIdx); context.EmitLdfld(typeof(CpuThreadState).GetField(nameof(CpuThreadState.CurrentTranslator), BindingFlags.Instance | BindingFlags.NonPublic)); context.EmitLdarg(TranslatedSub.StateArgIdx); context.EmitLdc_I8(imm); context.EmitLdc_I4((int)CallType.Call); context.EmitPrivateCall(typeof(Translator), nameof(Translator.GetOrTranslateSubroutine)); context.EmitLdarg(TranslatedSub.StateArgIdx); context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitCall(typeof(TranslatedSub), nameof(TranslatedSub.Execute)); } EmitContinueOrReturnCheck(context); }
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 EmitVectorInsertTmp(ILEmitterCtx context, int index, int size, long value) { ThrowIfInvalid(index, size); context.EmitLdc_I8(value); context.EmitLdvectmp(); context.EmitLdc_I4(index); context.EmitLdc_I4(size); VectorHelper.EmitCall(context, nameof(VectorHelper.VectorInsertInt)); context.EmitStvectmp(); }
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); } }
public static void Und(ILEmitterCtx context) { OpCode64 op = context.CurrOp; context.EmitStoreState(); context.EmitLdarg(TranslatedSub.StateArgIdx); context.EmitLdc_I8(op.Position); context.EmitLdc_I4(op.RawOpCode); context.EmitPrivateCall(typeof(CpuThreadState), nameof(CpuThreadState.OnUndefined)); if (context.CurrBlock.Next != null) { context.EmitLoadState(context.CurrBlock.Next); } else { context.EmitLdc_I8(op.Position + 4); context.Emit(OpCodes.Ret); } }
public static void B(ILEmitterCtx context) { OpCodeBImmAl64 op = (OpCodeBImmAl64)context.CurrOp; if (context.CurrBlock.Branch != null) { context.Emit(OpCodes.Br, context.GetLabel(op.Imm)); } else { context.EmitStoreState(); context.EmitLdc_I8(op.Imm); context.Emit(OpCodes.Ret); } }
public static void B(ILEmitterCtx context) { IOpCode32BImm op = (IOpCode32BImm)context.CurrOp; if (context.CurrBlock.Branch != null) { context.Emit(OpCodes.Br, context.GetLabel(op.Imm)); } else { context.EmitStoreContext(); context.EmitLdc_I8(op.Imm); context.Emit(OpCodes.Ret); } }
public static void Fmov_V(ILEmitterCtx context) { OpCodeSimdImm64 op = (OpCodeSimdImm64)context.CurrOp; int elems = op.RegisterSize == RegisterSize.Simd128 ? 4 : 2; for (int index = 0; index < (elems >> op.Size); index++) { context.EmitLdc_I8(op.Imm); EmitVectorInsert(context, op.Rd, index, op.Size + 2); } if (op.RegisterSize == RegisterSize.Simd64) { EmitVectorZeroUpper(context, op.Rd); } }
private static void EmitVectorShrImmNarrowOpZx(ILEmitterCtx context, bool round) { OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; int shift = GetImmShr(op); long roundConst = 1L << (shift - 1); int elems = 8 >> op.Size; int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0; if (part != 0) { context.EmitLdvec(op.Rd); context.EmitStvectmp(); } for (int index = 0; index < elems; index++) { EmitVectorExtractZx(context, op.Rn, index, op.Size + 1); if (round) { context.EmitLdc_I8(roundConst); context.Emit(OpCodes.Add); } context.EmitLdc_I4(shift); context.Emit(OpCodes.Shr_Un); EmitVectorInsertTmp(context, part + index, op.Size); } context.EmitLdvectmp(); context.EmitStvec(op.Rd); if (part == 0) { EmitVectorZeroUpper(context, op.Rd); } }
private static void EmitSimdMemWBack(ILEmitterCtx context, int offset) { OpCodeMemReg64 op = (OpCodeMemReg64)context.CurrOp; context.EmitLdint(op.Rn); if (op.Rm != RegisterAlias.Zr) { context.EmitLdint(op.Rm); } else { context.EmitLdc_I8(offset); } context.Emit(OpCodes.Add); context.EmitStint(op.Rn); }
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); } }