Add Cvt templates to macro_assembler-inl.h

And use these to implement MacroFCvtFloatToInteger.

Test: berberis_all

Change-Id: Ic0bccf3966db715a621cfa4e0b85dd3f036c9718
diff --git a/intrinsics/common_to_x86/include/berberis/intrinsics/macro_assembler-inl.h b/intrinsics/common_to_x86/include/berberis/intrinsics/macro_assembler-inl.h
index be43def..46fb882 100644
--- a/intrinsics/common_to_x86/include/berberis/intrinsics/macro_assembler-inl.h
+++ b/intrinsics/common_to_x86/include/berberis/intrinsics/macro_assembler-inl.h
@@ -55,6 +55,9 @@
 static constexpr bool kIntTypeWLQ =
     kFormatIs<IntType, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t>;
 
+template <typename IntType>
+static constexpr bool kIntTypeLQ = kFormatIs<IntType, int32_t, uint32_t, int64_t, uint64_t>;
+
 // Psr is the only asymmetric instruction where unsigned 64bit variant was supported in MMX in CPUs
 // released last century while signed 64bit variant is only added in AVX10 which is not yet even
 // available for purchase!
@@ -406,6 +409,77 @@
 DEFINE_XMM_MOV_INSTRUCTION(Vmov, (Register dest, XMMRegister src), (dest, src))
 #undef DEFINE_XMM_MOV_INSTRUCTION
 
+#define DEFINE_XMM_CVT_INSTRUCTION(insn_name, parameters, arguments)                           \
+  template <typename FormatFrom, typename FormatTo>                                            \
+  std::enable_if_t<kFloatType<FormatFrom> && kSignedIntType<FormatTo> && kIntTypeLQ<FormatTo>> \
+      insn_name parameters {                                                                   \
+    if constexpr (kFormatIs<FormatFrom, Float32> && kFormatIs<FormatTo, int32_t>) {            \
+      Assembler::insn_name##ss2sil arguments;                                                  \
+    } else if constexpr (kFormatIs<FormatFrom, Float32> && kFormatIs<FormatTo, int64_t>) {     \
+      Assembler::insn_name##ss2siq(dest, src);                                                 \
+    } else if constexpr (kFormatIs<FormatFrom, Float64> && kFormatIs<FormatTo, int32_t>) {     \
+      Assembler::insn_name##sd2sil(dest, src);                                                 \
+    } else {                                                                                   \
+      Assembler::insn_name##sd2siq(dest, src);                                                 \
+    }                                                                                          \
+  }
+DEFINE_XMM_CVT_INSTRUCTION(Cvt, (Register dest, XMMRegister src), (dest, src))
+DEFINE_XMM_CVT_INSTRUCTION(Cvt, (Register dest, Operand src), (dest, src))
+DEFINE_XMM_CVT_INSTRUCTION(Cvtt, (Register dest, XMMRegister src), (dest, src))
+DEFINE_XMM_CVT_INSTRUCTION(Cvtt, (Register dest, Operand src), (dest, src))
+DEFINE_XMM_CVT_INSTRUCTION(Vcvt, (Register dest, XMMRegister src), (dest, src))
+DEFINE_XMM_CVT_INSTRUCTION(Vcvt, (Register dest, Operand src), (dest, src))
+DEFINE_XMM_CVT_INSTRUCTION(Vcvtt, (Register dest, XMMRegister src), (dest, src))
+DEFINE_XMM_CVT_INSTRUCTION(Vcvtt, (Register dest, Operand src), (dest, src))
+#undef DEFINE_XMM_CVT_INSTRUCTION
+
+#define DEFINE_XMM_CVT_INSTRUCTION(insn_name, parameters, arguments)                             \
+  template <typename FormatFrom, typename FormatTo>                                              \
+  std::enable_if_t<kSignedIntType<FormatFrom> && kIntTypeWL<FormatFrom> && kFloatType<FormatTo>> \
+      insn_name parameters {                                                                     \
+    if constexpr (kFormatIs<FormatFrom, Float32> && kFormatIs<FormatTo, int32_t>) {              \
+      Assembler::insn_name##sil2ss arguments;                                                    \
+    } else if constexpr (kFormatIs<FormatFrom, Float32> && kFormatIs<FormatTo, int64_t>) {       \
+      Assembler::insn_name##siq2ss(dest, src);                                                   \
+    } else if constexpr (kFormatIs<FormatFrom, Float64> && kFormatIs<FormatTo, int32_t>) {       \
+      Assembler::insn_name##sil2sd(dest, src);                                                   \
+    } else {                                                                                     \
+      Assembler::insn_name##siq2sd(dest, src);                                                   \
+    }                                                                                            \
+  }
+DEFINE_XMM_CVT_INSTRUCTION(Cvt, (XMMRegister dest, Register src), (dest, src))
+DEFINE_XMM_CVT_INSTRUCTION(Cvt, (XMMRegister dest, Operand src), (dest, src))
+DEFINE_XMM_CVT_INSTRUCTION(Vcvt, (XMMRegister dest, Register src), (dest, src))
+DEFINE_XMM_CVT_INSTRUCTION(Vcvt, (XMMRegister dest, Operand src), (dest, src))
+#undef DEFINE_XMM_CVT_INSTRUCTION
+
+#define DEFINE_XMM_CVT_INSTRUCTION(insn_name, insn_suffix, parameters, arguments)   \
+  template <typename FormatFrom, typename FormatTo>                                 \
+  std::enable_if_t<kFloatType<FormatFrom> && kFloatType<FormatTo> &&                \
+                   sizeof(FormatFrom) != sizeof(FormatTo)>                          \
+      insn_name##insn_suffix parameters {                                           \
+    if constexpr (kFormatIs<FormatFrom, Float32> && kFormatIs<FormatTo, Float64>) { \
+      Assembler::insn_name##insn_suffix##s2##insn_suffix##d arguments;              \
+    } else {                                                                        \
+      Assembler::insn_name##insn_suffix##d2##insn_suffix##s arguments;              \
+    }                                                                               \
+  }
+DEFINE_XMM_CVT_INSTRUCTION(Cvt, p, (XMMRegister dest, XMMRegister src), (dest, src))
+DEFINE_XMM_CVT_INSTRUCTION(Cvt, p, (XMMRegister dest, Operand src), (dest, src))
+DEFINE_XMM_CVT_INSTRUCTION(Cvt, s, (XMMRegister dest, XMMRegister src), (dest, src))
+DEFINE_XMM_CVT_INSTRUCTION(Cvt, s, (XMMRegister dest, Operand src), (dest, src))
+DEFINE_XMM_CVT_INSTRUCTION(Vcvt, p, (XMMRegister dest, XMMRegister src), (dest, src))
+DEFINE_XMM_CVT_INSTRUCTION(Vcvt, p, (XMMRegister dest, Operand src), (dest, src))
+DEFINE_XMM_CVT_INSTRUCTION(Vcvt,
+                           s,
+                           (XMMRegister dest, XMMRegister src1, XMMRegister src2),
+                           (dest, src1, src2))
+DEFINE_XMM_CVT_INSTRUCTION(Vcvt,
+                           s,
+                           (XMMRegister dest, XMMRegister src1, Operand src2),
+                           (dest, src1, src2))
+#undef DEFINE_XMM_CVT_INSTRUCTION
+
 #define DEFINE_XMM_FLOAT_INSTRUCTION(insn_name, parameters, arguments) \
   template <typename format>                                           \
   std::enable_if_t<kFloatType<format>> insn_name parameters {          \
diff --git a/intrinsics/riscv64_to_x86_64/include/berberis/intrinsics/macro_assembler_floating_point_impl.h b/intrinsics/riscv64_to_x86_64/include/berberis/intrinsics/macro_assembler_floating_point_impl.h
index ff4f8ba..231f49a 100644
--- a/intrinsics/riscv64_to_x86_64/include/berberis/intrinsics/macro_assembler_floating_point_impl.h
+++ b/intrinsics/riscv64_to_x86_64/include/berberis/intrinsics/macro_assembler_floating_point_impl.h
@@ -361,16 +361,7 @@
 template <typename Assembler>
 template <typename FormatTo, typename FormatFrom>
 void MacroAssembler<Assembler>::MacroFCvtFloatToInteger(Register result, XMMRegister src) {
-  if constexpr (kFormatIs<FormatFrom, intrinsics::Float32> && kFormatIs<FormatTo, int32_t>) {
-    Assembler::Cvtss2sil(result, src);
-  } else if constexpr (kFormatIs<FormatFrom, intrinsics::Float32> && kFormatIs<FormatTo, int64_t>) {
-    Assembler::Cvtss2siq(result, src);
-  } else if constexpr (kFormatIs<FormatFrom, intrinsics::Float64> && kFormatIs<FormatTo, int32_t>) {
-    Assembler::Cvtsd2sil(result, src);
-  } else {
-    static_assert(kFormatIs<FormatFrom, intrinsics::Float64> && kFormatIs<FormatTo, int64_t>);
-    Assembler::Cvtsd2siq(result, src);
-  }
+  Cvt<FormatFrom, FormatTo>(result, src);
 }
 
 template <typename Assembler>