private static void EmitCsel(AILEmitterCtx Context, CselOperation CselOp) { AOpCodeCsel Op = (AOpCodeCsel)Context.CurrOp; AILLabel LblTrue = new AILLabel(); AILLabel LblEnd = new AILLabel(); Context.EmitCondBranch(LblTrue, Op.Cond); Context.EmitLdintzr(Op.Rm); if (CselOp == CselOperation.Increment) { Context.EmitLdc_I(1); Context.Emit(OpCodes.Add); } else if (CselOp == CselOperation.Invert) { Context.Emit(OpCodes.Not); } else if (CselOp == CselOperation.Negate) { Context.Emit(OpCodes.Neg); } Context.Emit(OpCodes.Br_S, LblEnd); Context.MarkLabel(LblTrue); Context.EmitLdintzr(Op.Rn); Context.MarkLabel(LblEnd); Context.EmitStintzr(Op.Rd); }
public static void Fccmp_S(AILEmitterCtx Context) { AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp; AILLabel LblTrue = new AILLabel(); AILLabel LblEnd = new AILLabel(); Context.EmitCondBranch(LblTrue, Op.Cond); //TODO: Share this logic with Ccmp. Context.EmitLdc_I4((Op.NZCV >> 0) & 1); Context.EmitStflg((int)APState.VBit); Context.EmitLdc_I4((Op.NZCV >> 1) & 1); Context.EmitStflg((int)APState.CBit); Context.EmitLdc_I4((Op.NZCV >> 2) & 1); Context.EmitStflg((int)APState.ZBit); Context.EmitLdc_I4((Op.NZCV >> 3) & 1); Context.EmitStflg((int)APState.NBit); Context.Emit(OpCodes.Br_S, LblEnd); Context.MarkLabel(LblTrue); Fcmp_S(Context); Context.MarkLabel(LblEnd); }
private static void EmitCcmp(AILEmitterCtx Context, CcmpOp CmpOp) { AOpCodeCcmp Op = (AOpCodeCcmp)Context.CurrOp; AILLabel LblTrue = new AILLabel(); AILLabel LblEnd = new AILLabel(); Context.EmitCondBranch(LblTrue, Op.Cond); Context.EmitLdc_I4((Op.NZCV >> 0) & 1); Context.EmitStflg((int)APState.VBit); Context.EmitLdc_I4((Op.NZCV >> 1) & 1); Context.EmitStflg((int)APState.CBit); Context.EmitLdc_I4((Op.NZCV >> 2) & 1); Context.EmitStflg((int)APState.ZBit); Context.EmitLdc_I4((Op.NZCV >> 3) & 1); Context.EmitStflg((int)APState.NBit); Context.Emit(OpCodes.Br_S, LblEnd); Context.MarkLabel(LblTrue); EmitDataLoadOpers(Context); if (CmpOp == CcmpOp.Cmp) { Context.Emit(OpCodes.Sub); Context.EmitZNFlagCheck(); EmitSubsCCheck(Context); EmitSubsVCheck(Context); } else if (CmpOp == CcmpOp.Cmn) { Context.Emit(OpCodes.Add); Context.EmitZNFlagCheck(); EmitAddsCCheck(Context); EmitAddsVCheck(Context); } else { throw new ArgumentException(nameof(CmpOp)); } Context.Emit(OpCodes.Pop); Context.MarkLabel(LblEnd); }
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 EmitFcmp(AILEmitterCtx Context, OpCode ILOp, int Index, bool Scalar) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; int SizeF = Op.Size & 1; ulong SzMask = ulong.MaxValue >> (64 - (32 << SizeF)); EmitVectorExtractF(Context, Op.Rn, Index, SizeF); if (Op is AOpCodeSimdReg BinOp) { EmitVectorExtractF(Context, BinOp.Rm, Index, SizeF); } else if (SizeF == 0) { Context.EmitLdc_R4(0); } else /* if (SizeF == 1) */ { Context.EmitLdc_R8(0); } AILLabel LblTrue = new AILLabel(); AILLabel LblEnd = new AILLabel(); Context.Emit(ILOp, LblTrue); if (Scalar) { EmitVectorZeroAll(Context, Op.Rd); } else { EmitVectorInsert(Context, Op.Rd, Index, SizeF + 2, 0); } Context.Emit(OpCodes.Br_S, LblEnd); Context.MarkLabel(LblTrue); if (Scalar) { EmitVectorInsert(Context, Op.Rd, Index, 3, (long)SzMask); EmitVectorZeroUpper(Context, Op.Rd); } else { EmitVectorInsert(Context, Op.Rd, Index, SizeF + 2, (long)SzMask); } Context.MarkLabel(LblEnd); }
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); }); }
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); } }
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); } }
public static void Fccmp_S(AILEmitterCtx Context) { AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp; AILLabel LblTrue = new AILLabel(); AILLabel LblEnd = new AILLabel(); Context.EmitCondBranch(LblTrue, Op.Cond); EmitSetNZCV(Context, Op.NZCV); Context.Emit(OpCodes.Br, LblEnd); Context.MarkLabel(LblTrue); Fcmp_S(Context); Context.MarkLabel(LblEnd); }
private static void EmitCmp(AILEmitterCtx Context, OpCode ILOp, bool Scalar) { AOpCodeSimd Op = (AOpCodeSimd)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 AOpCodeSimdReg BinOp) { EmitVectorExtractSx(Context, BinOp.Rm, Index, Op.Size); } else { Context.EmitLdc_I8(0); } AILLabel LblTrue = new AILLabel(); AILLabel LblEnd = new AILLabel(); 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 == ARegisterSize.SIMD64) || Scalar) { EmitVectorZeroUpper(Context, Op.Rd); } }
public static void Fcsel_S(AILEmitterCtx Context) { AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp; AILLabel LblTrue = new AILLabel(); AILLabel LblEnd = new AILLabel(); Context.EmitCondBranch(LblTrue, Op.Cond); Context.EmitLdvecsf(Op.Rm); Context.EmitStvecsf(Op.Rd); Context.Emit(OpCodes.Br_S, LblEnd); Context.MarkLabel(LblTrue); Context.EmitLdvecsf(Op.Rn); Context.EmitStvecsf(Op.Rd); Context.MarkLabel(LblEnd); }
public static void Fcsel_S(AILEmitterCtx Context) { AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp; AILLabel LblTrue = new AILLabel(); AILLabel LblEnd = new AILLabel(); Context.EmitCondBranch(LblTrue, Op.Cond); EmitVectorExtractF(Context, Op.Rm, 0, Op.Size); Context.Emit(OpCodes.Br_S, LblEnd); Context.MarkLabel(LblTrue); EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); Context.MarkLabel(LblEnd); EmitScalarSetF(Context, Op.Rd, Op.Size); }
private static void EmitAbs(AILEmitterCtx Context) { AILLabel LblTrue = new AILLabel(); Context.Emit(OpCodes.Dup); Context.Emit(OpCodes.Ldc_I4_0); Context.Emit(OpCodes.Bge_S, LblTrue); Context.Emit(OpCodes.Neg); Context.MarkLabel(LblTrue); }
public static void Cmtst_V(AILEmitterCtx Context) { AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; int Bytes = Context.CurrOp.GetBitsCount() >> 3; ulong SzMask = ulong.MaxValue >> (64 - (8 << Op.Size)); for (int Index = 0; Index < (Bytes >> Op.Size); Index++) { EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size); EmitVectorExtractZx(Context, Op.Rm, Index, Op.Size); AILLabel LblTrue = new AILLabel(); AILLabel LblEnd = new AILLabel(); Context.Emit(OpCodes.And); Context.EmitLdc_I4(0); 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 == ARegisterSize.SIMD64) { EmitVectorZeroUpper(Context, Op.Rd); } }
private static void EmitDiv(AILEmitterCtx Context, OpCode ILOp) { //If Rm == 0, Rd = 0 (division by zero). Context.EmitLdc_I(0); EmitDataLoadRm(Context); Context.EmitLdc_I(0); AILLabel BadDiv = new AILLabel(); 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); EmitDataLoadRn(Context); Context.EmitLdc_I(IntMin); Context.Emit(OpCodes.Ceq); EmitDataLoadRm(Context); Context.EmitLdc_I(-1); Context.Emit(OpCodes.Ceq); Context.Emit(OpCodes.And); Context.Emit(OpCodes.Brtrue_S, BadDiv); Context.Emit(OpCodes.Pop); } EmitDataLoadRn(Context); EmitDataLoadRm(Context); Context.Emit(ILOp); Context.MarkLabel(BadDiv); EmitDataStore(Context); }
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); //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 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); } }
// 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 Fcmp_S(AILEmitterCtx Context) { AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; bool CmpWithZero = !(Op is AOpCodeSimdFcond) ? Op.Bit3 : false; //todo //Context.TryMarkCondWithoutCmp(); void EmitLoadOpers() { Context.EmitLdvecsf(Op.Rn); if (CmpWithZero) { EmitLdcImmF(Context, 0, Op.Size); } else { Context.EmitLdvecsf(Op.Rm); } } //Z = Rn == Rm EmitLoadOpers(); Context.Emit(OpCodes.Ceq); Context.Emit(OpCodes.Dup); Context.EmitStflg((int)APState.ZBit); //C = Rn >= Rm EmitLoadOpers(); Context.Emit(OpCodes.Cgt); Context.Emit(OpCodes.Or); Context.EmitStflg((int)APState.CBit); //N = Rn < Rm EmitLoadOpers(); Context.Emit(OpCodes.Clt); Context.EmitStflg((int)APState.NBit); //Handle NaN case. If any number is NaN, then NZCV = 0011. AILLabel LblNotNaN = new AILLabel(); if (CmpWithZero) { EmitNaNCheck(Context, Op.Rn); } else { EmitNaNCheck(Context, Op.Rn); EmitNaNCheck(Context, Op.Rm); Context.Emit(OpCodes.Or); } Context.Emit(OpCodes.Brfalse_S, LblNotNaN); Context.EmitLdc_I4(1); Context.EmitLdc_I4(1); Context.EmitStflg((int)APState.CBit); Context.EmitStflg((int)APState.VBit); Context.MarkLabel(LblNotNaN); }
public static void EmitSaturatingNarrowOp( AILEmitterCtx Context, Action Emit, bool SignedSrc, bool SignedDst, bool Scalar) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; int Elems = !Scalar ? 8 >> Op.Size : 1; int ESize = 8 << Op.Size; int Part = !Scalar && (Op.RegisterSize == ARegisterSize.SIMD128) ? Elems : 0; long TMaxValue = SignedDst ? (1 << (ESize - 1)) - 1 : (1L << ESize) - 1L; long TMinValue = SignedDst ? -((1 << (ESize - 1))) : 0; Context.EmitLdc_I8(0L); Context.EmitSttmp(); if (Part != 0) { Context.EmitLdvec(Op.Rd); Context.EmitStvectmp(); } for (int Index = 0; Index < Elems; Index++) { AILLabel LblLe = new AILLabel(); AILLabel LblGeEnd = new AILLabel(); EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, SignedSrc); Emit(); Context.Emit(OpCodes.Dup); Context.EmitLdc_I8(TMaxValue); Context.Emit(SignedSrc ? OpCodes.Ble_S : OpCodes.Ble_Un_S, LblLe); Context.Emit(OpCodes.Pop); Context.EmitLdc_I8(TMaxValue); Context.EmitLdc_I8(0x8000000L); Context.EmitSttmp(); Context.Emit(OpCodes.Br_S, LblGeEnd); Context.MarkLabel(LblLe); Context.Emit(OpCodes.Dup); Context.EmitLdc_I8(TMinValue); Context.Emit(SignedSrc ? OpCodes.Bge_S : OpCodes.Bge_Un_S, LblGeEnd); Context.Emit(OpCodes.Pop); Context.EmitLdc_I8(TMinValue); Context.EmitLdc_I8(0x8000000L); Context.EmitSttmp(); Context.MarkLabel(LblGeEnd); if (Scalar) { EmitVectorZeroLower(Context, Op.Rd); } EmitVectorInsertTmp(Context, Part + Index, Op.Size); } Context.EmitLdvectmp(); Context.EmitStvec(Op.Rd); 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)); }
public static void Fcmp_S(AILEmitterCtx Context) { AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; bool CmpWithZero = !(Op is AOpCodeSimdFcond) ? Op.Bit3 : false; //Handle NaN case. //If any number is NaN, then NZCV = 0011. if (CmpWithZero) { EmitNaNCheck(Context, Op.Rn); } else { EmitNaNCheck(Context, Op.Rn); EmitNaNCheck(Context, Op.Rm); Context.Emit(OpCodes.Or); } AILLabel LblNaN = new AILLabel(); AILLabel LblEnd = new AILLabel(); Context.Emit(OpCodes.Brtrue_S, LblNaN); void EmitLoadOpers() { EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); if (CmpWithZero) { if (Op.Size == 0) { Context.EmitLdc_R4(0); } else /* if (SizeF == 1) */ { Context.EmitLdc_R8(0); } } else { EmitVectorExtractF(Context, Op.Rm, 0, Op.Size); } } //Z = Rn == Rm EmitLoadOpers(); Context.Emit(OpCodes.Ceq); Context.Emit(OpCodes.Dup); Context.EmitStflg((int)APState.ZBit); //C = Rn >= Rm EmitLoadOpers(); Context.Emit(OpCodes.Cgt); Context.Emit(OpCodes.Or); Context.EmitStflg((int)APState.CBit); //N = Rn < Rm EmitLoadOpers(); Context.Emit(OpCodes.Clt); Context.EmitStflg((int)APState.NBit); //V = 0 Context.EmitLdc_I4(0); Context.EmitStflg((int)APState.VBit); Context.Emit(OpCodes.Br_S, LblEnd); Context.MarkLabel(LblNaN); EmitSetNZCV(Context, 0b0011); Context.MarkLabel(LblEnd); }
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)); }