private static void EmitBranch(AILEmitterCtx Context, OpCode ILOp) { AOpCodeBImm Op = (AOpCodeBImm)Context.CurrOp; if (Context.CurrBlock.Next != null && Context.CurrBlock.Branch != null) { Context.Emit(ILOp, Context.GetLabel(Op.Imm)); } else { Context.EmitStoreState(); AILLabel LblTaken = new AILLabel(); Context.Emit(ILOp, LblTaken); 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 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); } }
private static void EmitDoublingMultiplyHighHalf(AILEmitterCtx Context, bool Round) { AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; int ESize = 8 << Op.Size; Context.Emit(OpCodes.Mul); if (!Round) { Context.EmitAsr(ESize - 1); } else { long RoundConst = 1L << (ESize - 1); AILLabel LblTrue = new AILLabel(); Context.EmitLsl(1); Context.EmitLdc_I8(RoundConst); Context.Emit(OpCodes.Add); Context.EmitAsr(ESize); Context.Emit(OpCodes.Dup); Context.EmitLdc_I8((long)int.MinValue); Context.Emit(OpCodes.Bne_Un_S, LblTrue); Context.Emit(OpCodes.Neg); Context.MarkLabel(LblTrue); } }
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; } } }
private static void EmitVectorImmBinaryOp(AILEmitterCtx Context, Action Emit, long Imm, bool Signed) { AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; int Bytes = Context.CurrOp.GetBitsCount() >> 3; for (int Index = 0; Index < (Bytes >> Op.Size); Index++) { Context.EmitLdvec(Op.Rd); Context.EmitLdc_I4(Index); Context.EmitLdc_I4(Op.Size); EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed); Context.EmitLdc_I8(Imm); Emit(); ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InsertVec)); Context.EmitStvec(Op.Rd); } if (Op.RegisterSize == ARegisterSize.SIMD64) { EmitVectorZeroUpper(Context, Op.Rd); } }
public static void EmitVectorImmOp(AILEmitterCtx Context, Action Emit, bool Binary) { AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp; int Bytes = Context.CurrOp.GetBitsCount() >> 3; for (int Index = 0; Index < (Bytes >> Op.Size); 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 == ARegisterSize.SIMD64) { EmitVectorZeroUpper(Context, Op.Rd); } }
public static void Sli_V(AILEmitterCtx Context) { AOpCodeSimdShImm Op = (AOpCodeSimdShImm)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 == ARegisterSize.SIMD64) { EmitVectorZeroUpper(Context, Op.Rd); } }
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); } }
private static void EmitHighNarrow(AILEmitterCtx Context, Action Emit, bool Round) { AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; int Elems = 8 >> Op.Size; int ESize = 8 << Op.Size; int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; for (int Index = 0; Index < Elems; Index++) { EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size + 1); EmitVectorExtractZx(Context, Op.Rm, Index, Op.Size + 1); Emit(); if (Round) { Context.EmitLdc_I8(1L << (ESize - 1)); Context.Emit(OpCodes.Add); } Context.EmitLsr(ESize); EmitVectorInsert(Context, Op.Rd, Part + Index, Op.Size); } if (Part == 0) { EmitVectorZeroUpper(Context, Op.Rd); } }
public static void Fmov_Si(AILEmitterCtx Context) { AOpCodeSimdFmov Op = (AOpCodeSimdFmov)Context.CurrOp; Context.EmitLdc_I8(Op.Imm); EmitScalarSet(Context, Op.Rd, Op.Size + 2); }
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 EmitShrImmOp(AILEmitterCtx Context, ShrImmFlags Flags) { AOpCodeSimdShImm Op = (AOpCodeSimdShImm)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) */ { EmitShrImm_64(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 == ARegisterSize.SIMD64) || Scalar) { EmitVectorZeroUpper(Context, Op.Rd); } }
private static void EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size, long Value) { Context.EmitLdvec(Reg); Context.EmitLdc_I4(Index); Context.EmitLdc_I4(Size); Context.EmitLdc_I8(Value); ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InsertVec)); Context.EmitStvec(Reg); }
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 Fmov_S(AILEmitterCtx Context) { AOpCodeSimdFmov Op = (AOpCodeSimdFmov)Context.CurrOp; Context.EmitLdc_I8(Op.Imm); Context.EmitLdc_I4(0); Context.EmitLdc_I4(Op.Size + 2); ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Fmov_S)); Context.EmitStvec(Op.Rd); }
private static void EmitVectorShl(AILEmitterCtx Context, bool Signed) { //This instruction shifts the value on vector A by the number of bits //specified on the signed, lower 8 bits of vector B. If the shift value //is greater or equal to the data size of each lane, then the result is zero. //Additionally, negative shifts produces right shifts by the negated shift value. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; int MaxShift = 8 << Op.Size; EmitVectorBinaryZx(Context, () => { AILLabel LblShl = new AILLabel(); AILLabel LblZero = new AILLabel(); AILLabel LblEnd = new AILLabel(); void EmitShift(OpCode ILOp) { Context.Emit(OpCodes.Dup); Context.EmitLdc_I4(MaxShift); Context.Emit(OpCodes.Bge_S, LblZero); Context.Emit(ILOp); Context.Emit(OpCodes.Br_S, LblEnd); } Context.Emit(OpCodes.Conv_I1); Context.Emit(OpCodes.Dup); Context.EmitLdc_I4(0); Context.Emit(OpCodes.Bge_S, LblShl); Context.Emit(OpCodes.Neg); EmitShift(Signed ? OpCodes.Shr : OpCodes.Shr_Un); Context.MarkLabel(LblShl); EmitShift(OpCodes.Shl); Context.MarkLabel(LblZero); Context.Emit(OpCodes.Pop); Context.Emit(OpCodes.Pop); Context.EmitLdc_I8(0); Context.MarkLabel(LblEnd); }); }
// Dst_64 = (Int(Src_64, Signed) + RoundConst) >> Shift; private static void EmitShrImm_64( AILEmitterCtx Context, bool Signed, long RoundConst, int Shift) { Context.EmitLdc_I8(RoundConst); Context.EmitLdc_I4(Shift); ASoftFallback.EmitCall(Context, Signed ? nameof(ASoftFallback.SignedShrImm_64) : nameof(ASoftFallback.UnsignedShrImm_64)); }
public static void Bl(AILEmitterCtx Context) { AOpCodeBImmAl Op = (AOpCodeBImmAl)Context.CurrOp; Context.EmitLdc_I(Op.Position + 4); Context.EmitStint(ARegisters.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); if (Context.CurrBlock.Next != null) { Context.EmitLoadState(Context.CurrBlock.Next); } } else { Context.EmitLdc_I8(Op.Imm); Context.Emit(OpCodes.Ret); } }
public static void EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size, long Value) { ThrowIfInvalid(Index, Size); Context.EmitLdc_I8(Value); Context.EmitLdvec(Reg); Context.EmitLdc_I4(Index); Context.EmitLdc_I4(Size); AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInsertInt)); Context.EmitStvec(Reg); }
private static void EmitMovi_V(AILEmitterCtx Context, bool Not) { AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp; Context.EmitLdc_I8(Not ? ~Op.Imm : Op.Imm); Context.EmitLdc_I4(Op.Size); ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Dup_Gp64), nameof(ASoftFallback.Dup_Gp128)); Context.EmitStvec(Op.Rd); }
public static void Fmov_V(AILEmitterCtx Context) { AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp; Context.EmitLdc_I8(Op.Imm); Context.EmitLdc_I4(Op.Size + 2); ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Dup_Gp64), nameof(ASoftFallback.Dup_Gp128)); Context.EmitStvec(Op.Rd); }
public static void Bic_Vi(AILEmitterCtx Context) { AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp; Context.EmitLdvec(Op.Rd); Context.EmitLdc_I8(Op.Imm); Context.EmitLdc_I4(Op.Size); ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Bic_Vi64), nameof(ASoftFallback.Bic_Vi128)); Context.EmitStvec(Op.Rd); }
// TSrc (8bit, 16bit, 32bit, 64bit) == TDst (8bit, 16bit, 32bit, 64bit); signed. public static void EmitUnarySignedSatQAbsOrNeg(AILEmitterCtx Context, int Size) { int ESize = 8 << Size; long TMaxValue = (1L << (ESize - 1)) - 1L; long TMinValue = -(1L << (ESize - 1)); AILLabel LblFalse = new AILLabel(); Context.Emit(OpCodes.Dup); Context.Emit(OpCodes.Neg); Context.EmitLdc_I8(TMinValue); Context.Emit(OpCodes.Ceq); Context.Emit(OpCodes.Brfalse_S, LblFalse); Context.Emit(OpCodes.Pop); EmitSetFpsrQCFlag(Context); Context.EmitLdc_I8(TMaxValue); Context.MarkLabel(LblFalse); }
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 B(AILEmitterCtx Context) { AOpCodeBImmAl Op = (AOpCodeBImmAl)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 EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size, long Value) { if (Size < 0 || Size > 3) { throw new ArgumentOutOfRangeException(nameof(Size)); } Context.EmitLdc_I8(Value); Context.EmitLdvec(Reg); Context.EmitLdc_I4(Index); Context.EmitLdc_I4(Size); ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertInt)); Context.EmitStvec(Reg); }
public static void Fmov_V(AILEmitterCtx Context) { AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp; int Elems = Op.RegisterSize == ARegisterSize.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 == ARegisterSize.SIMD64) { EmitVectorZeroUpper(Context, Op.Rd); } }