private static void EmitLoad(AILEmitterCtx Context, AccessType AccType, bool Pair) { AOpCodeMemEx Op = (AOpCodeMemEx)Context.CurrOp; if (AccType.HasFlag(AccessType.Ordered)) { EmitBarrier(Context); } if (AccType.HasFlag(AccessType.Exclusive)) { EmitMemoryCall(Context, nameof(AMemory.SetExclusive), Op.Rn); } Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); Context.EmitLdint(Op.Rn); EmitReadZxCall(Context, Op.Size); Context.EmitStintzr(Op.Rt); if (Pair) { Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); Context.EmitLdint(Op.Rn); Context.EmitLdc_I(8 << Op.Size); Context.Emit(OpCodes.Add); EmitReadZxCall(Context, Op.Size); Context.EmitStintzr(Op.Rt2); } }
private static void EmitStore(AILEmitterCtx Context, AccessType AccType, bool Pair) { AOpCodeMemEx Op = (AOpCodeMemEx)Context.CurrOp; bool Ordered = (AccType & AccessType.Ordered) != 0; bool Exclusive = (AccType & AccessType.Exclusive) != 0; if (Ordered) { EmitBarrier(Context); } AILLabel LblEx = new AILLabel(); AILLabel LblEnd = new AILLabel(); if (Exclusive) { EmitMemoryCall(Context, nameof(AMemory.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(ATranslatedSub.MemoryArgIdx); Context.EmitLdint(Op.Rn); Context.EmitLdintzr(Op.Rt); EmitWriteCall(Context, Op.Size); if (Pair) { Context.EmitLdarg(ATranslatedSub.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(AMemory.ClearExclusiveForStore)); } Context.MarkLabel(LblEnd); }
private static void EmitSimdMemMs(AILEmitterCtx Context, bool IsLoad) { AOpCodeSimdMemMs Op = (AOpCodeSimdMemMs)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(ATranslatedSub.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 == ARegisterSize.SIMD64 && Elem == Op.Elems - 1) { EmitVectorZeroUpper(Context, Rtt); } } else { Context.EmitLdarg(ATranslatedSub.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); } }
private static void EmitMemoryCall(AILEmitterCtx Context, string Name, int Rn = -1) { Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); Context.EmitLdarg(ATranslatedSub.StateArgIdx); if (Rn != -1) { Context.EmitLdint(Rn); } Context.EmitCall(typeof(AMemory), Name); }
private static void EmitSimdMemSs(AILEmitterCtx Context, bool IsLoad) { AOpCodeSimdMemSs Op = (AOpCodeSimdMemSs)Context.CurrOp; //TODO: Replicate mode. int Offset = 0; for (int SElem = 0; SElem < Op.SElems; SElem++) { int Rt = (Op.Rt + SElem) & 0x1f; if (IsLoad) { Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); Context.EmitLdint(Op.Rn); Context.EmitLdc_I8(Offset); Context.Emit(OpCodes.Add); EmitReadZxCall(Context, Op.Size); EmitVectorInsert(Context, Rt, Op.Index, Op.Size); if (Op.RegisterSize == ARegisterSize.SIMD64) { EmitVectorZeroUpper(Context, Rt); } } else { Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); Context.EmitLdint(Op.Rn); Context.EmitLdc_I8(Offset); Context.Emit(OpCodes.Add); EmitVectorExtractZx(Context, Rt, Op.Index, Op.Size); EmitWriteCall(Context, Op.Size); } Offset += 1 << Op.Size; } if (Op.WBack) { EmitSimdMemWBack(Context, Offset); } }
public static void EmitSetFpsrQCFlag(AILEmitterCtx Context) { const int QCFlagBit = 27; Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpsr)); Context.EmitLdc_I4(1 << QCFlagBit); Context.Emit(OpCodes.Or); Context.EmitCallPropSet(typeof(AThreadState), nameof(AThreadState.Fpsr)); }
public static void EmitLdr(AILEmitterCtx Context, bool Signed) { AOpCodeMem Op = (AOpCodeMem)Context.CurrOp; Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); EmitLoadAddress(Context); if (Signed && Op.Extend64) { EmitReadSx64Call(Context, Op.Size); } else if (Signed) { EmitReadSx32Call(Context, Op.Size); } else { EmitReadZxCall(Context, Op.Size); } if (Op is IAOpCodeSimd) { Context.EmitStvec(Op.Rt); } else { Context.EmitStintzr(Op.Rt); } EmitWBackIfNeeded(Context); }
public static void Msr(AILEmitterCtx Context) { AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp; Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitLdintzr(Op.Rt); string PropName; switch (GetPackedId(Op)) { case 0b11_011_0100_0100_000: PropName = nameof(AThreadState.Fpcr); break; case 0b11_011_0100_0100_001: PropName = nameof(AThreadState.Fpsr); break; case 0b11_011_1101_0000_010: PropName = nameof(AThreadState.TpidrEl0); break; default: throw new NotImplementedException($"Unknown MSR at {Op.Position:x16}"); } PropertyInfo PropInfo = typeof(AThreadState).GetProperty(PropName); if (PropInfo.PropertyType != typeof(long) && PropInfo.PropertyType != typeof(ulong)) { Context.Emit(OpCodes.Conv_U4); } Context.EmitCallPropSet(typeof(AThreadState), PropName); }
public static void Fcvtl_V(AILEmitterCtx Context) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; int SizeF = Op.Size & 1; int Elems = 4 >> SizeF; int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; for (int Index = 0; Index < Elems; Index++) { if (SizeF == 0) { EmitVectorExtractZx(Context, Op.Rn, Part + Index, 1); Context.Emit(OpCodes.Conv_U2); Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitCall(typeof(ASoftFloat16_32), nameof(ASoftFloat16_32.FPConvert)); } else /* if (SizeF == 1) */ { EmitVectorExtractF(Context, Op.Rn, Part + Index, 0); Context.Emit(OpCodes.Conv_R8); } EmitVectorInsertTmpF(Context, Index, SizeF); } Context.EmitLdvectmp(); Context.EmitStvec(Op.Rd); }
public static void Sys(AILEmitterCtx 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. AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp; switch (GetPackedId(Op)) { case 0b11_011_0111_0100_001: { //DC ZVA for (int Offs = 0; Offs < (4 << AThreadState.DczSizeLog2); Offs += 8) { Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); Context.EmitLdint(Op.Rt); Context.EmitLdc_I(Offs); Context.Emit(OpCodes.Add); Context.EmitLdc_I8(0); AInstEmitMemoryHelper.EmitWriteCall(Context, 3); } break; } } }
public static void LdrLit(AILEmitterCtx Context) { IAOpCodeLit Op = (IAOpCodeLit)Context.CurrOp; if (Op.Prefetch) { return; } Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); Context.EmitLdc_I8(Op.Imm); if (Op.Signed) { EmitReadSx64Call(Context, Op.Size); } else { EmitReadZxCall(Context, Op.Size); } if (Op is IAOpCodeSimd) { Context.EmitStvec(Op.Rt); } else { Context.EmitStint(Op.Rt); } }
// TSrc (16bit, 32bit, 64bit; signed, unsigned) > TDst (8bit, 16bit, 32bit; signed, unsigned). public static void EmitSatQ( AILEmitterCtx Context, int SizeDst, bool SignedSrc, bool SignedDst) { if (SizeDst > 2) { throw new ArgumentOutOfRangeException(nameof(SizeDst)); } Context.EmitLdc_I4(SizeDst); Context.EmitLdarg(ATranslatedSub.StateArgIdx); if (SignedSrc) { ASoftFallback.EmitCall(Context, SignedDst ? nameof(ASoftFallback.SignedSrcSignedDstSatQ) : nameof(ASoftFallback.SignedSrcUnsignedDstSatQ)); } else { ASoftFallback.EmitCall(Context, SignedDst ? nameof(ASoftFallback.UnsignedSrcSignedDstSatQ) : nameof(ASoftFallback.UnsignedSrcUnsignedDstSatQ)); } }
public static void Frinti_V(AILEmitterCtx Context) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; int SizeF = Op.Size & 1; EmitVectorUnaryOpF(Context, () => { Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpcr)); if (SizeF == 0) { AVectorHelper.EmitCall(Context, nameof(AVectorHelper.RoundF)); } else if (SizeF == 1) { AVectorHelper.EmitCall(Context, nameof(AVectorHelper.Round)); } else { throw new InvalidOperationException(); } }); }
public static void Und(AILEmitterCtx Context) { AOpCode Op = Context.CurrOp; Context.EmitStoreState(); Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitLdc_I8(Op.Position); Context.EmitLdc_I4(Op.RawOpCode); string MthdName = nameof(AThreadState.OnUndefined); MethodInfo MthdInfo = typeof(AThreadState).GetMethod(MthdName, Binding); Context.EmitCall(MthdInfo); if (Context.CurrBlock.Next != null) { Context.EmitLoadState(Context.CurrBlock.Next); } else { Context.EmitLdc_I8(Op.Position + 4); Context.Emit(OpCodes.Ret); } }
// TSrc (64bit) == TDst (64bit); signed. public static void EmitUnarySignedSatQAbsOrNeg(AILEmitterCtx Context) { if (((AOpCodeSimd)Context.CurrOp).Size < 3) { throw new InvalidOperationException(); } Context.EmitLdarg(ATranslatedSub.StateArgIdx); ASoftFallback.EmitCall(Context, nameof(ASoftFallback.UnarySignedSatQAbsOrNeg)); }
public static void Ldp(AILEmitterCtx Context) { AOpCodeMemPair Op = (AOpCodeMemPair)Context.CurrOp; void EmitReadAndStore(int Rt) { if (Op.Extend64) { EmitReadSx64Call(Context, Op.Size); } else { EmitReadZxCall(Context, Op.Size); } if (Op is IAOpCodeSimd) { Context.EmitStvec(Rt); } else { Context.EmitStintzr(Rt); } } Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); EmitLoadAddress(Context); EmitReadAndStore(Op.Rt); Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); Context.EmitLdtmp(); Context.EmitLdc_I8(1 << Op.Size); Context.Emit(OpCodes.Add); EmitReadAndStore(Op.Rt2); EmitWBackIfNeeded(Context); }
private static void EmitExceptionCall(AILEmitterCtx Context, string MthdName) { AOpCodeException Op = (AOpCodeException)Context.CurrOp; Context.EmitStoreState(); Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitLdc_I4(Op.Id); MethodInfo MthdInfo = typeof(AThreadState).GetMethod(MthdName, Binding); Context.EmitCall(MthdInfo); //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(ATranslatedSub.StateArgIdx); Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Running)); AILLabel LblEnd = new AILLabel(); 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 EmitSoftFloatCall(AILEmitterCtx Context, string Name) { IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; Type Type = (Op.Size & 1) == 0 ? typeof(ASoftFloat_32) : typeof(ASoftFloat_64); Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitCall(Type, Name); }
// TSrcs (64bit) == TDst (64bit); signed, unsigned. public static void EmitBinarySatQAccumulate(AILEmitterCtx Context, bool Signed) { if (((AOpCodeSimd)Context.CurrOp).Size < 3) { throw new InvalidOperationException(); } Context.EmitLdarg(ATranslatedSub.StateArgIdx); ASoftFallback.EmitCall(Context, Signed ? nameof(ASoftFallback.BinarySignedSatQAcc) : nameof(ASoftFallback.BinaryUnsignedSatQAcc)); }
public static void Stp(AILEmitterCtx Context) { AOpCodeMemPair Op = (AOpCodeMemPair)Context.CurrOp; Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); EmitLoadAddress(Context); if (Op is IAOpCodeSimd) { Context.EmitLdvec(Op.Rt); } else { Context.EmitLdintzr(Op.Rt); } EmitWriteCall(Context, Op.Size); Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); Context.EmitLdtmp(); Context.EmitLdc_I8(1 << Op.Size); Context.Emit(OpCodes.Add); if (Op is IAOpCodeSimd) { Context.EmitLdvec(Op.Rt2); } else { Context.EmitLdintzr(Op.Rt2); } EmitWriteCall(Context, Op.Size); EmitWBackIfNeeded(Context); }
public static void Ret(AILEmitterCtx Context) { if (AOptimizations.GenerateCallStack) { Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitPrivateCall(typeof(AThreadState), nameof(AThreadState.ExitMethod)); } Context.EmitStoreState(); Context.EmitLdint(AThreadState.LRIndex); Context.Emit(OpCodes.Ret); }
public static void Svc(AILEmitterCtx Context) { AOpCodeException Op = (AOpCodeException)Context.CurrOp; Context.EmitStoreState(); Context.EmitLdarg(ATranslatedSub.RegistersArgIdx); Context.EmitLdc_I4(Op.Id); Context.EmitCall(typeof(ARegisters), nameof(ARegisters.OnSvcCall)); if (Context.CurrBlock.Next != null) { Context.EmitLoadState(Context.CurrBlock.Next); } }
public static void Br(AILEmitterCtx Context) { AOpCodeBReg Op = (AOpCodeBReg)Context.CurrOp; if (AOptimizations.GenerateCallStack) { Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitLdintzr(Op.Rn); Context.EmitPrivateCall(typeof(AThreadState), nameof(AThreadState.JumpMethod)); } Context.EmitStoreState(); Context.EmitLdintzr(Op.Rn); Context.Emit(OpCodes.Ret); }
public static void Bl(AILEmitterCtx Context) { AOpCodeBImmAl Op = (AOpCodeBImmAl)Context.CurrOp; if (AOptimizations.GenerateCallStack) { Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitLdc_I8(Op.Imm); Context.EmitPrivateCall(typeof(AThreadState), nameof(AThreadState.EnterMethod)); } Context.EmitLdc_I(Op.Position + 4); Context.EmitStint(AThreadState.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); AILLabel LblContinue = new AILLabel(); 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); } }
private static void EmitExceptionCall(AILEmitterCtx Context, string MthdName) { AOpCodeException Op = (AOpCodeException)Context.CurrOp; Context.EmitStoreState(); Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitLdc_I4(Op.Id); MethodInfo MthdInfo = typeof(AThreadState).GetMethod(MthdName, Binding); Context.EmitCall(MthdInfo); if (Context.CurrBlock.Next != null) { Context.EmitLoadState(Context.CurrBlock.Next); } }
public static void Mrs(AILEmitterCtx Context) { AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp; Context.EmitLdarg(ATranslatedSub.RegistersArgIdx); string PropName; switch (GetPackedId(Op)) { case 0b11_011_0000_0000_001: PropName = nameof(ARegisters.CtrEl0); break; case 0b11_011_0000_0000_111: PropName = nameof(ARegisters.DczidEl0); break; case 0b11_011_0100_0100_000: PropName = nameof(ARegisters.Fpcr); break; case 0b11_011_0100_0100_001: PropName = nameof(ARegisters.Fpsr); break; case 0b11_011_1101_0000_010: PropName = nameof(ARegisters.TpidrEl0); break; case 0b11_011_1101_0000_011: PropName = nameof(ARegisters.Tpidr); break; case 0b11_011_1110_0000_001: PropName = nameof(ARegisters.CntpctEl0); break; default: throw new NotImplementedException($"Unknown MRS at {Op.Position:x16}"); } Context.EmitCallPropGet(typeof(ARegisters), PropName); PropertyInfo PropInfo = typeof(ARegisters).GetProperty(PropName); if (PropInfo.PropertyType != typeof(long) && PropInfo.PropertyType != typeof(ulong)) { Context.Emit(OpCodes.Conv_U8); } Context.EmitStintzr(Op.Rt); }
public static void Und(AILEmitterCtx Context) { AOpCode Op = Context.CurrOp; Context.EmitStoreState(); Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitLdc_I8(Op.Position); Context.EmitLdc_I4(Op.RawOpCode); Context.EmitPrivateCall(typeof(AThreadState), nameof(AThreadState.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 Frintx_S(AILEmitterCtx Context) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; EmitScalarUnaryOpF(Context, () => { Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpcr)); if (Op.Size == 0) { ASoftFallback.EmitCall(Context, nameof(ASoftFallback.RoundF)); } else if (Op.Size == 1) { ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Round)); } else { throw new InvalidOperationException(); } }); }
private static void EmitQxtn(AILEmitterCtx Context, bool Signed, bool Scalar) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; int Elems = (!Scalar ? 8 >> Op.Size : 1); int ESize = 8 << Op.Size; int TMaxValue = (Signed ? (1 << (ESize - 1)) - 1 : (int)((1L << ESize) - 1L)); int TMinValue = (Signed ? -((1 << (ESize - 1))) : 0); int Part = (!Scalar & (Op.RegisterSize == ARegisterSize.SIMD128) ? Elems : 0); Context.EmitLdc_I8(0L); Context.EmitSttmp(); for (int Index = 0; Index < Elems; Index++) { AILLabel LblLe = new AILLabel(); AILLabel LblGeEnd = new AILLabel(); EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, Signed); Context.Emit(OpCodes.Dup); Context.EmitLdc_I4(TMaxValue); Context.Emit(OpCodes.Conv_U8); Context.Emit(Signed ? OpCodes.Ble_S : OpCodes.Ble_Un_S, LblLe); Context.Emit(OpCodes.Pop); Context.EmitLdc_I4(TMaxValue); Context.EmitLdc_I8(0x8000000L); Context.EmitSttmp(); Context.Emit(OpCodes.Br_S, LblGeEnd); Context.MarkLabel(LblLe); Context.Emit(OpCodes.Dup); Context.EmitLdc_I4(TMinValue); Context.Emit(OpCodes.Conv_I8); Context.Emit(Signed ? OpCodes.Bge_S : OpCodes.Bge_Un_S, LblGeEnd); Context.Emit(OpCodes.Pop); Context.EmitLdc_I4(TMinValue); Context.EmitLdc_I8(0x8000000L); Context.EmitSttmp(); Context.MarkLabel(LblGeEnd); if (Scalar) { EmitVectorZeroLower(Context, Op.Rd); } EmitVectorInsert(Context, Op.Rd, Part + Index, Op.Size); } if (Part == 0) { EmitVectorZeroUpper(Context, Op.Rd); } Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpsr)); Context.EmitLdtmp(); Context.Emit(OpCodes.Conv_I4); Context.Emit(OpCodes.Or); Context.EmitCallPropSet(typeof(AThreadState), nameof(AThreadState.Fpsr)); }
private static void EmitSimdMemSs(AILEmitterCtx Context, bool IsLoad) { AOpCodeSimdMemSs Op = (AOpCodeSimdMemSs)Context.CurrOp; int Offset = 0; void EmitMemAddress() { Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); Context.EmitLdint(Op.Rn); Context.EmitLdc_I8(Offset); Context.Emit(OpCodes.Add); } if (Op.Replicate) { //Only loads uses the replicate mode. if (!IsLoad) { throw new InvalidOperationException(); } int Bytes = Context.CurrOp.GetBitsCount() >> 3; for (int SElem = 0; SElem < Op.SElems; SElem++) { int Rt = (Op.Rt + SElem) & 0x1f; for (int Index = 0; Index < (Bytes >> Op.Size); Index++) { EmitMemAddress(); EmitReadZxCall(Context, Op.Size); EmitVectorInsert(Context, Rt, Index, Op.Size); } if (Op.RegisterSize == ARegisterSize.SIMD64) { EmitVectorZeroUpper(Context, Rt); } Offset += 1 << Op.Size; } } else { for (int SElem = 0; SElem < Op.SElems; SElem++) { int Rt = (Op.Rt + SElem) & 0x1f; if (IsLoad) { EmitMemAddress(); EmitReadZxCall(Context, Op.Size); EmitVectorInsert(Context, Rt, Op.Index, Op.Size); } else { EmitMemAddress(); EmitVectorExtractZx(Context, Rt, Op.Index, Op.Size); EmitWriteCall(Context, Op.Size); } Offset += 1 << Op.Size; } } if (Op.WBack) { EmitSimdMemWBack(Context, Offset); } }