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 EmitLoadAddress(AILEmitterCtx Context) { switch (Context.CurrOp) { case AOpCodeMemImm Op: Context.EmitLdint(Op.Rn); if (!Op.PostIdx) { //Pre-indexing. Context.EmitLdc_I(Op.Imm); Context.Emit(OpCodes.Add); } break; case AOpCodeMemReg Op: Context.EmitLdint(Op.Rn); Context.EmitLdintzr(Op.Rm); Context.EmitCast(Op.IntType); if (Op.Shift) { Context.EmitLsl(Op.Size); } Context.Emit(OpCodes.Add); break; } //Save address to Scratch var since the register value may change. Context.Emit(OpCodes.Dup); Context.EmitSttmp(); }
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 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 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 Ret(AILEmitterCtx Context) { Context.EmitStoreState(); Context.EmitLdint(AThreadState.LRIndex); Context.Emit(OpCodes.Ret); }
private static void EmitSimdMemWBack(AILEmitterCtx Context, int Offset) { AOpCodeMemReg Op = (AOpCodeMemReg)Context.CurrOp; Context.EmitLdint(Op.Rn); if (Op.Rm != ARegisters.ZRIndex) { Context.EmitLdint(Op.Rm); } else { Context.EmitLdc_I8(Offset); } Context.Emit(OpCodes.Add); Context.EmitStint(Op.Rn); }
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); }
public static void EmitDataLoadRn(AILEmitterCtx Context) { IAOpCodeAlu Op = (IAOpCodeAlu)Context.CurrOp; if (Op.DataOp == ADataOp.Logical || Op is IAOpCodeAluRs) { Context.EmitLdintzr(Op.Rn); } else { Context.EmitLdint(Op.Rn); } }
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); }
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); } }
private static void EmitSimdMultLdSt(AILEmitterCtx Context, bool IsLoad) { AOpCodeSimdMemMult Op = (AOpCodeSimdMemMult)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.EmitLdvec(Rtt); Context.EmitLdc_I4(Elem); Context.EmitLdc_I4(Op.Size); Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); Context.EmitLdint(Op.Rn); Context.EmitLdc_I8(Offset); Context.Emit(OpCodes.Add); EmitReadZxCall(Context, Op.Size); ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InsertVec)); Context.EmitStvec(Rtt); 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); Context.EmitLdvec(Rtt); Context.EmitLdc_I4(Elem); Context.EmitLdc_I4(Op.Size); ASoftFallback.EmitCall(Context, nameof(ASoftFallback.ExtractVec)); EmitWriteCall(Context, Op.Size); } Offset += 1 << Op.Size; } } } if (Op.WBack) { Context.EmitLdint(Op.Rn); if (Op.Rm != ARegisters.ZRIndex) { Context.EmitLdint(Op.Rm); } else { Context.EmitLdc_I8(Offset); } Context.Emit(OpCodes.Add); Context.EmitStint(Op.Rn); } }