public static void Vcvt_FD(ArmEmitterContext context) { OpCode32SimdS op = (OpCode32SimdS)context.CurrOp; int vm = op.Vm; int vd; if (op.Size == 3) { vd = FlipVdBits(op.Vd, false); // Double to single. Operand fp = ExtractScalar(context, OperandType.FP64, vm); Operand res = context.ConvertToFP(OperandType.FP32, fp); InsertScalar(context, vd, res); } else { vd = FlipVdBits(op.Vd, true); // Single to double. Operand fp = ExtractScalar(context, OperandType.FP32, vm); Operand res = context.ConvertToFP(OperandType.FP64, fp); InsertScalar(context, vd, res); } }
public static void Fcvtn_V(ArmEmitterContext context) { OpCodeSimd op = (OpCodeSimd)context.CurrOp; int sizeF = op.Size & 1; if (Optimizations.UseSse2 && sizeF == 1) { Operand d = GetVec(op.Rd); Operand n = GetVec(op.Rn); Operand res = context.AddIntrinsic(Intrinsic.X86Movlhps, d, context.VectorZero()); Operand nInt = context.AddIntrinsic(Intrinsic.X86Cvtpd2ps, n); nInt = context.AddIntrinsic(Intrinsic.X86Movlhps, nInt, nInt); Intrinsic movInst = op.RegisterSize == RegisterSize.Simd128 ? Intrinsic.X86Movlhps : Intrinsic.X86Movhlps; res = context.AddIntrinsic(movInst, res, nInt); context.Copy(GetVec(op.Rd), res); } else { OperandType type = sizeF == 0 ? OperandType.FP32 : OperandType.FP64; int elems = 4 >> sizeF; int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0; Operand res = part == 0 ? context.VectorZero() : context.Copy(GetVec(op.Rd)); for (int index = 0; index < elems; index++) { Operand ne = context.VectorExtract(type, GetVec(op.Rn), 0); if (sizeF == 0) { Delegate dlg = new _U16_F32(SoftFloat32_16.FPConvert); Operand e = context.Call(dlg, ne); e = context.ZeroExtend16(OperandType.I64, e); res = EmitVectorInsert(context, res, e, part + index, 1); } else /* if (sizeF == 1) */ { Operand e = context.ConvertToFP(OperandType.FP32, ne); res = context.VectorInsert(res, e, part + index); } } context.Copy(GetVec(op.Rd), res); } }
public static void Fcvtl_V(ArmEmitterContext context) { OpCodeSimd op = (OpCodeSimd)context.CurrOp; int sizeF = op.Size & 1; if (Optimizations.UseSse2 && sizeF == 1) { Operand n = GetVec(op.Rn); Operand res; if (op.RegisterSize == RegisterSize.Simd128) { res = context.AddIntrinsic(Intrinsic.X86Movhlps, n, n); } else { res = n; } res = context.AddIntrinsic(Intrinsic.X86Cvtps2pd, res); context.Copy(GetVec(op.Rd), res); } else { Operand res = context.VectorZero(); int elems = 4 >> sizeF; int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0; for (int index = 0; index < elems; index++) { if (sizeF == 0) { Operand ne = EmitVectorExtractZx(context, op.Rn, part + index, 1); Delegate dlg = new _F32_U16(SoftFloat16_32.FPConvert); Operand e = context.Call(dlg, ne); res = context.VectorInsert(res, e, index); } else /* if (sizeF == 1) */ { Operand ne = context.VectorExtract(OperandType.FP32, GetVec(op.Rn), part + index); Operand e = context.ConvertToFP(OperandType.FP64, ne); res = context.VectorInsert(res, e, index); } } context.Copy(GetVec(op.Rd), res); } }
private static Operand EmitFPConvert(ArmEmitterContext context, Operand value, OperandType type, bool signed) { Debug.Assert(value.Type == OperandType.I32 || value.Type == OperandType.I64); if (signed) { return(context.ConvertToFP(type, value)); } else { return(context.ConvertToFPUI(type, value)); } }
private static Operand EmitFPConvert(ArmEmitterContext context, Operand value, int size, bool signed) { Debug.Assert(value.Type == OperandType.I32 || value.Type == OperandType.I64); Debug.Assert((uint)size < 2); OperandType type = size == 0 ? OperandType.FP32 : OperandType.FP64; if (signed) { return(context.ConvertToFP(type, value)); } else { return(context.ConvertToFPUI(type, value)); } }
public static void Fcvt_S(ArmEmitterContext context) { OpCodeSimd op = (OpCodeSimd)context.CurrOp; if (op.Size == 0 && op.Opc == 1) // Single -> Double. { if (Optimizations.UseSse2) { Operand n = GetVec(op.Rn); Operand res = context.AddIntrinsic(Intrinsic.X86Cvtss2sd, context.VectorZero(), n); context.Copy(GetVec(op.Rd), res); } else { Operand ne = context.VectorExtract(OperandType.FP32, GetVec(op.Rn), 0); Operand res = context.ConvertToFP(OperandType.FP64, ne); context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0)); } } else if (op.Size == 1 && op.Opc == 0) // Double -> Single. { if (Optimizations.UseSse2) { Operand n = GetVec(op.Rn); Operand res = context.AddIntrinsic(Intrinsic.X86Cvtsd2ss, context.VectorZero(), n); context.Copy(GetVec(op.Rd), res); } else { Operand ne = context.VectorExtract(OperandType.FP64, GetVec(op.Rn), 0); Operand res = context.ConvertToFP(OperandType.FP32, ne); context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0)); } } else if (op.Size == 0 && op.Opc == 3) // Single -> Half. { Operand ne = context.VectorExtract(OperandType.FP32, GetVec(op.Rn), 0); Delegate dlg = new _U16_F32(SoftFloat32_16.FPConvert); Operand res = context.Call(dlg, ne); res = context.ZeroExtend16(OperandType.I64, res); context.Copy(GetVec(op.Rd), EmitVectorInsert(context, context.VectorZero(), res, 0, 1)); } else if (op.Size == 3 && op.Opc == 0) // Half -> Single. { Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1); Delegate dlg = new _F32_U16(SoftFloat16_32.FPConvert); Operand res = context.Call(dlg, ne); context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0)); } else if (op.Size == 1 && op.Opc == 3) // Double -> Half. { throw new NotImplementedException("Double-precision to half-precision."); } else if (op.Size == 3 && op.Opc == 1) // Double -> Half. { throw new NotImplementedException("Half-precision to double-precision."); } else // Invalid encoding. { Debug.Assert(false, $"type == {op.Size} && opc == {op.Opc}"); } }
// VCVT: convert vector elements (32-bit) between floating-point and fixed point public static void Vcvt_V2(ArmEmitterContext context) { OpCode32SimdCvtFFixed op = (OpCode32SimdCvtFFixed)context.CurrOp; var toFixed = op.Opc == 1; int fracBits = op.Fbits; var unsigned = op.U; // Sign of I32 (destination/source) if (toFixed) // F32 to S32 or U32 (fixed) { EmitVectorUnaryOpF32(context, (op1) => { var a = context.Multiply(op1, ConstF(MathF.Pow(2f, fracBits))); var rounded = EmitUnaryMathCall(context, nameof(MathF.Truncate), a); MethodInfo info = unsigned ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)) : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32)); return(context.Call(info, rounded)); }); } else // S32 or U32 (fixed) to F32 { EmitVectorUnaryOpI32(context, (op1) => { var f = unsigned ? context.ConvertToFPUI(OperandType.FP32, op1) : context.ConvertToFP(OperandType.FP32, op1); return(context.Multiply(f, ConstF(1f / MathF.Pow(2f, fracBits)))); }, !unsigned); } }