// VRINTA/M/N/P (floating-point). public static void Vrint_RM(ArmEmitterContext context) { OpCode32SimdS op = (OpCode32SimdS)context.CurrOp; OperandType floatSize = op.RegisterSize == RegisterSize.Int64 ? OperandType.FP64 : OperandType.FP32; int rm = op.Opc2 & 3; if (Optimizations.UseSse2 && rm != 0b00) { EmitScalarUnaryOpSimd32(context, (m) => { Intrinsic inst = (op.Size & 1) == 0 ? Intrinsic.X86Roundss : Intrinsic.X86Roundsd; FPRoundingMode roundMode = RMToRoundMode(rm); return(context.AddIntrinsic(inst, m, Const(X86GetRoundControl(roundMode)))); }); } else { Operand toConvert = ExtractScalar(context, floatSize, op.Vm); switch (rm) { case 0b00: // Away toConvert = EmitRoundMathCall(context, MidpointRounding.AwayFromZero, toConvert); break; case 0b01: // Nearest toConvert = EmitRoundMathCall(context, MidpointRounding.ToEven, toConvert); break; case 0b10: // Towards positive infinity toConvert = EmitUnaryMathCall(context, nameof(Math.Ceiling), toConvert); break; case 0b11: // Towards negative infinity toConvert = EmitUnaryMathCall(context, nameof(Math.Floor), toConvert); break; } InsertScalar(context, op.Vd, toConvert); } }
public static float RoundF(float value) { ExecutionContext context = NativeInterface.GetContext(); FPRoundingMode roundMode = context.Fpcr.GetRoundingMode(); if (roundMode == FPRoundingMode.ToNearest) { return(MathF.Round(value)); // even } else if (roundMode == FPRoundingMode.TowardsPlusInfinity) { return(MathF.Ceiling(value)); } else if (roundMode == FPRoundingMode.TowardsMinusInfinity) { return(MathF.Floor(value)); } else /* if (roundMode == FPRoundingMode.TowardsZero) */ { return(MathF.Truncate(value)); } }
private static void EmitSse41ConvertVector32(ArmEmitterContext context, FPRoundingMode roundMode, bool signed) { OpCode32Simd op = (OpCode32Simd)context.CurrOp; EmitVectorUnaryOpSimd32(context, (n) => { int sizeF = op.Size & 1; if (sizeF == 0) { Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpps, n, n, Const((int)CmpCondition.OrderedQ)); nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n); nRes = context.AddIntrinsic(Intrinsic.X86Roundps, nRes, Const(X86GetRoundControl(roundMode))); Operand zero = context.VectorZero(); Operand nCmp; if (!signed) { nCmp = context.AddIntrinsic(Intrinsic.X86Cmpps, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); } Operand fpMaxValMask = X86GetAllElements(context, 0x4F000000); // 2.14748365E9f (2147483648) Operand nInt = context.AddIntrinsic(Intrinsic.X86Cvtps2dq, nRes); Operand nInt2 = default; if (!signed) { nRes = context.AddIntrinsic(Intrinsic.X86Subps, nRes, fpMaxValMask); nCmp = context.AddIntrinsic(Intrinsic.X86Cmpps, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); nInt2 = context.AddIntrinsic(Intrinsic.X86Cvtps2dq, nRes); } nRes = context.AddIntrinsic(Intrinsic.X86Cmpps, nRes, fpMaxValMask, Const((int)CmpCondition.NotLessThan)); if (signed) { return(context.AddIntrinsic(Intrinsic.X86Pxor, nInt, nRes)); } else { Operand dRes = context.AddIntrinsic(Intrinsic.X86Pxor, nInt2, nRes); return(context.AddIntrinsic(Intrinsic.X86Paddd, dRes, nInt)); } } else /* if (sizeF == 1) */ { Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmppd, n, n, Const((int)CmpCondition.OrderedQ)); nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n); nRes = context.AddIntrinsic(Intrinsic.X86Roundpd, nRes, Const(X86GetRoundControl(roundMode))); Operand zero = context.VectorZero(); Operand nCmp; if (!signed) { nCmp = context.AddIntrinsic(Intrinsic.X86Cmppd, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); } Operand fpMaxValMask = X86GetAllElements(context, 0x43E0000000000000L); // 9.2233720368547760E18d (9223372036854775808) Operand nLong = InstEmit.EmitSse2CvtDoubleToInt64OpF(context, nRes, false); Operand nLong2 = default; if (!signed) { nRes = context.AddIntrinsic(Intrinsic.X86Subpd, nRes, fpMaxValMask); nCmp = context.AddIntrinsic(Intrinsic.X86Cmppd, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); nLong2 = InstEmit.EmitSse2CvtDoubleToInt64OpF(context, nRes, false); } nRes = context.AddIntrinsic(Intrinsic.X86Cmppd, nRes, fpMaxValMask, Const((int)CmpCondition.NotLessThan)); if (signed) { return(context.AddIntrinsic(Intrinsic.X86Pxor, nLong, nRes)); } else { Operand dRes = context.AddIntrinsic(Intrinsic.X86Pxor, nLong2, nRes); return(context.AddIntrinsic(Intrinsic.X86Paddq, dRes, nLong)); } } }); }
private static void EmitSse41ConvertInt32(ArmEmitterContext context, FPRoundingMode roundMode, bool signed) { // A port of the similar round function in InstEmitSimdCvt. OpCode32SimdCvtFI op = (OpCode32SimdCvtFI)context.CurrOp; bool doubleSize = (op.Size & 1) != 0; int shift = doubleSize ? 1 : 2; Operand n = GetVecA32(op.Vm >> shift); n = EmitSwapScalar(context, n, op.Vm, doubleSize); if (!doubleSize) { Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpss, n, n, Const((int)CmpCondition.OrderedQ)); nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n); nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode))); Operand zero = context.VectorZero(); Operand nCmp; Operand nIntOrLong2 = default; if (!signed) { nCmp = context.AddIntrinsic(Intrinsic.X86Cmpss, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); } int fpMaxVal = 0x4F000000; // 2.14748365E9f (2147483648) Operand fpMaxValMask = X86GetScalar(context, fpMaxVal); Operand nIntOrLong = context.AddIntrinsicInt(Intrinsic.X86Cvtss2si, nRes); if (!signed) { nRes = context.AddIntrinsic(Intrinsic.X86Subss, nRes, fpMaxValMask); nCmp = context.AddIntrinsic(Intrinsic.X86Cmpss, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); nIntOrLong2 = context.AddIntrinsicInt(Intrinsic.X86Cvtss2si, nRes); } nRes = context.AddIntrinsic(Intrinsic.X86Cmpss, nRes, fpMaxValMask, Const((int)CmpCondition.NotLessThan)); Operand nInt = context.AddIntrinsicInt(Intrinsic.X86Cvtsi2si, nRes); Operand dRes; if (signed) { dRes = context.BitwiseExclusiveOr(nIntOrLong, nInt); } else { dRes = context.BitwiseExclusiveOr(nIntOrLong2, nInt); dRes = context.Add(dRes, nIntOrLong); } InsertScalar(context, op.Vd, dRes); } else { Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpsd, n, n, Const((int)CmpCondition.OrderedQ)); nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n); nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode))); Operand zero = context.VectorZero(); Operand nCmp; Operand nIntOrLong2 = default; if (!signed) { nCmp = context.AddIntrinsic(Intrinsic.X86Cmpsd, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); } long fpMaxVal = 0x41E0000000000000L; // 2147483648.0000000d (2147483648) Operand fpMaxValMask = X86GetScalar(context, fpMaxVal); Operand nIntOrLong = context.AddIntrinsicInt(Intrinsic.X86Cvtsd2si, nRes); if (!signed) { nRes = context.AddIntrinsic(Intrinsic.X86Subsd, nRes, fpMaxValMask); nCmp = context.AddIntrinsic(Intrinsic.X86Cmpsd, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); nIntOrLong2 = context.AddIntrinsicInt(Intrinsic.X86Cvtsd2si, nRes); } nRes = context.AddIntrinsic(Intrinsic.X86Cmpsd, nRes, fpMaxValMask, Const((int)CmpCondition.NotLessThan)); Operand nLong = context.AddIntrinsicLong(Intrinsic.X86Cvtsi2si, nRes); nLong = context.ConvertI64ToI32(nLong); Operand dRes; if (signed) { dRes = context.BitwiseExclusiveOr(nIntOrLong, nLong); } else { dRes = context.BitwiseExclusiveOr(nIntOrLong2, nLong); dRes = context.Add(dRes, nIntOrLong); } InsertScalar(context, op.Vd, dRes); } }
private static void EmitSse41Fcvtu(ArmEmitterContext context, FPRoundingMode roundMode, bool scalar) { OpCodeSimd op = (OpCodeSimd)context.CurrOp; Operand n = GetVec(op.Rn); // sizeF == ((OpCodeSimdShImm)op).Size - 2 int sizeF = op.Size & 1; if (sizeF == 0) { Operand nMask = context.AddIntrinsic(Intrinsic.X86Cmpps, n, n, Const((int)CmpCondition.OrderedQ)); Operand nScaled = context.AddIntrinsic(Intrinsic.X86Pand, nMask, n); if (op is OpCodeSimdShImm fixedOp) { int fBits = GetImmShr(fixedOp); // BitConverter.Int32BitsToSingle(fpScaled) == MathF.Pow(2f, fBits) int fpScaled = 0x3F800000 + fBits * 0x800000; Operand scale = X86GetAllElements(context, fpScaled); nScaled = context.AddIntrinsic(Intrinsic.X86Mulps, nScaled, scale); } Operand nRnd = context.AddIntrinsic(Intrinsic.X86Roundps, nScaled, Const(X86GetRoundControl(roundMode))); Operand nRndMask = context.AddIntrinsic(Intrinsic.X86Cmpps, nRnd, context.VectorZero(), Const((int)CmpCondition.NotLessThanOrEqual)); Operand nRndMasked = context.AddIntrinsic(Intrinsic.X86Pand, nRnd, nRndMask); Operand nInt = context.AddIntrinsic(Intrinsic.X86Cvtps2dq, nRndMasked); Operand mask = X86GetAllElements(context, 0x4F000000); // 2.14748365E9f (2147483648) Operand res = context.AddIntrinsic(Intrinsic.X86Subps, nRndMasked, mask); Operand mask2 = context.AddIntrinsic(Intrinsic.X86Cmpps, res, context.VectorZero(), Const((int)CmpCondition.NotLessThanOrEqual)); Operand resMasked = context.AddIntrinsic(Intrinsic.X86Pand, res, mask2); res = context.AddIntrinsic(Intrinsic.X86Cvtps2dq, resMasked); Operand mask3 = context.AddIntrinsic(Intrinsic.X86Cmpps, resMasked, mask, Const((int)CmpCondition.NotLessThan)); res = context.AddIntrinsic(Intrinsic.X86Pxor, res, mask3); res = context.AddIntrinsic(Intrinsic.X86Paddd, res, nInt); if (scalar) { res = context.VectorZeroUpper96(res); } else if (op.RegisterSize == RegisterSize.Simd64) { res = context.VectorZeroUpper64(res); } context.Copy(GetVec(op.Rd), res); } else /* if (sizeF == 1) */ { Operand nMask = context.AddIntrinsic(Intrinsic.X86Cmppd, n, n, Const((int)CmpCondition.OrderedQ)); Operand nScaled = context.AddIntrinsic(Intrinsic.X86Pand, nMask, n); if (op is OpCodeSimdShImm fixedOp) { int fBits = GetImmShr(fixedOp); // BitConverter.Int64BitsToDouble(fpScaled) == Math.Pow(2d, fBits) long fpScaled = 0x3FF0000000000000L + fBits * 0x10000000000000L; Operand scale = X86GetAllElements(context, fpScaled); nScaled = context.AddIntrinsic(Intrinsic.X86Mulpd, nScaled, scale); } Operand nRnd = context.AddIntrinsic(Intrinsic.X86Roundpd, nScaled, Const(X86GetRoundControl(roundMode))); Operand nRndMask = context.AddIntrinsic(Intrinsic.X86Cmppd, nRnd, context.VectorZero(), Const((int)CmpCondition.NotLessThanOrEqual)); Operand nRndMasked = context.AddIntrinsic(Intrinsic.X86Pand, nRnd, nRndMask); Operand high; if (!scalar) { high = context.AddIntrinsic(Intrinsic.X86Unpckhpd, nRndMasked, nRndMasked); high = context.AddIntrinsicLong(Intrinsic.X86Cvtsd2si, high); } else { high = Const(0L); } Operand low = context.AddIntrinsicLong(Intrinsic.X86Cvtsd2si, nRndMasked); Operand nInt = EmitVectorLongCreate(context, low, high); Operand mask = X86GetAllElements(context, 0x43E0000000000000L); // 9.2233720368547760E18d (9223372036854775808) Operand res = context.AddIntrinsic(Intrinsic.X86Subpd, nRndMasked, mask); Operand mask2 = context.AddIntrinsic(Intrinsic.X86Cmppd, res, context.VectorZero(), Const((int)CmpCondition.NotLessThanOrEqual)); Operand resMasked = context.AddIntrinsic(Intrinsic.X86Pand, res, mask2); if (!scalar) { high = context.AddIntrinsic(Intrinsic.X86Unpckhpd, resMasked, resMasked); high = context.AddIntrinsicLong(Intrinsic.X86Cvtsd2si, high); } low = context.AddIntrinsicLong(Intrinsic.X86Cvtsd2si, resMasked); res = EmitVectorLongCreate(context, low, high); Operand mask3 = context.AddIntrinsic(Intrinsic.X86Cmppd, resMasked, mask, Const((int)CmpCondition.NotLessThan)); res = context.AddIntrinsic(Intrinsic.X86Pxor, res, mask3); res = context.AddIntrinsic(Intrinsic.X86Paddq, res, nInt); if (scalar) { res = context.VectorZeroUpper64(res); } context.Copy(GetVec(op.Rd), res); } }
public Instruction OpenClVstorea_halfn_r(Instruction resultType, Instruction data, Instruction offset, Instruction p, FPRoundingMode mode) { return(ExtInst(resultType, AddExtInstImport("OpenCL.std"), 181, data, offset, p, LiteralInteger.CreateForEnum(mode))); }