aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure/Instructions
diff options
context:
space:
mode:
Diffstat (limited to 'ARMeilleure/Instructions')
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdCvt32.cs62
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdHelper32.cs16
2 files changed, 78 insertions, 0 deletions
diff --git a/ARMeilleure/Instructions/InstEmitSimdCvt32.cs b/ARMeilleure/Instructions/InstEmitSimdCvt32.cs
index c76634eb..ba713feb 100644
--- a/ARMeilleure/Instructions/InstEmitSimdCvt32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdCvt32.cs
@@ -261,6 +261,68 @@ namespace ARMeilleure.Instructions
}
}
+ public static void Vcvt_TB(ArmEmitterContext context)
+ {
+ OpCode32SimdCvtTB op = (OpCode32SimdCvtTB)context.CurrOp;
+
+ if (Optimizations.UseF16c)
+ {
+ Debug.Assert(!Optimizations.ForceLegacySse);
+
+ if (op.Op)
+ {
+ Operand res = ExtractScalar(context, op.Size == 1 ? OperandType.FP64 : OperandType.FP32, op.Vm);
+ if (op.Size == 1)
+ {
+ res = context.AddIntrinsic(Intrinsic.X86Cvtsd2ss, context.VectorZero(), res);
+ }
+ res = context.AddIntrinsic(Intrinsic.X86Vcvtps2ph, res, Const(X86GetRoundControl(FPRoundingMode.ToNearest)));
+ res = context.VectorExtract16(res, 0);
+ InsertScalar16(context, op.Vd, op.T, res);
+ }
+ else
+ {
+ Operand res = context.VectorCreateScalar(ExtractScalar16(context, op.Vm, op.T));
+ res = context.AddIntrinsic(Intrinsic.X86Vcvtph2ps, res);
+ if (op.Size == 1)
+ {
+ res = context.AddIntrinsic(Intrinsic.X86Cvtss2sd, context.VectorZero(), res);
+ }
+ res = context.VectorExtract(op.Size == 1 ? OperandType.I64 : OperandType.I32, res, 0);
+ InsertScalar(context, op.Vd, res);
+ }
+ }
+ else
+ {
+ if (op.Op)
+ {
+ // Convert to half
+
+ Operand src = ExtractScalar(context, op.Size == 1 ? OperandType.FP64 : OperandType.FP32, op.Vm);
+
+ MethodInfo method = op.Size == 1
+ ? typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert))
+ : typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert));
+ Operand res = context.Call(method, src);
+
+ InsertScalar16(context, op.Vd, op.T, res);
+ }
+ else
+ {
+ // Convert from half
+
+ Operand src = ExtractScalar16(context, op.Vm, op.T);
+
+ MethodInfo method = op.Size == 1
+ ? typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert))
+ : typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert));
+ Operand res = context.Call(method, src);
+
+ InsertScalar(context, op.Vd, res);
+ }
+ }
+ }
+
// VRINTA/M/N/P (floating-point).
public static void Vrint_RM(ArmEmitterContext context)
{
diff --git a/ARMeilleure/Instructions/InstEmitSimdHelper32.cs b/ARMeilleure/Instructions/InstEmitSimdHelper32.cs
index 0620ea33..84b01d05 100644
--- a/ARMeilleure/Instructions/InstEmitSimdHelper32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdHelper32.cs
@@ -70,6 +70,22 @@ namespace ARMeilleure.Instructions
context.Copy(vec, insert);
}
+ public static Operand ExtractScalar16(ArmEmitterContext context, int reg, bool top)
+ {
+ return context.VectorExtract16(GetVecA32(reg >> 2), ((reg & 3) << 1) | (top ? 1 : 0));
+ }
+
+ public static void InsertScalar16(ArmEmitterContext context, int reg, bool top, Operand value)
+ {
+ Debug.Assert(value.Type == OperandType.FP32 || value.Type == OperandType.I32);
+
+ Operand vec, insert;
+ vec = GetVecA32(reg >> 2);
+ insert = context.VectorInsert16(vec, value, ((reg & 3) << 1) | (top ? 1 : 0));
+
+ context.Copy(vec, insert);
+ }
+
public static Operand ExtractElement(ArmEmitterContext context, int reg, int size, bool signed)
{
return EmitVectorExtract32(context, reg >> (4 - size), reg & ((16 >> size) - 1), size, signed);