#pragma once #include "gi_common.h" #if defined(GI_SUPPORT_F16) //! c + b * a #if defined(GI_NEON_INTRINSICS) #if defined(__ARM_FEATURE_FMA) #define v_fma_ps_f16(c, b, a) vfmaq_f16((c), (b), (a)) #define v_fma_n_f16(c, b, a) vfmaq_n_f16((c), (b), (a)) #else #define v_fma_ps_f16(c, b, a) vaddq_f16((c), vmulq_f16((b), (a))) #define v_fma_n_f16(c, b, a) vaddq_f16((c), vmulq_f16((b), vdupq_n_f16(a))) #endif #endif GI_FORCEINLINE GI_FLOAT16_t GiBroadcastFloat16(gi_float16_t Value) { #if defined(GI_NEON_INTRINSICS) return vdupq_n_f16(Value); #elif defined(GI_RVV_INTRINSICS) return vfmv_v_f_f16m1(Value, GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)); #endif } GI_FORCEINLINE GI_FLOAT16_t GiLoadBroadcastFloat16(const gi_float16_t* Value) { #if defined(GI_NEON_INTRINSICS) return vld1q_dup_f16(Value); #elif defined(GI_RVV_INTRINSICS) return GiBroadcastFloat16(*Value); #endif } GI_FORCEINLINE GI_FLOAT32_V2_t GiCastFloat16ToFloat32(const GI_FLOAT16_t& fp16) { #if defined(GI_NEON_INTRINSICS) GI_FLOAT32_V2_t ret; GiSetSubVectorFloat32V2(ret, 0, vcvt_f32_f16(vget_low_f16(fp16))); GiSetSubVectorFloat32V2(ret, 1, vcvt_f32_f16(vget_high_f16(fp16))); return ret; #elif defined(GI_RVV_INTRINSICS) GI_FLOAT32_V2_t ret; vfloat32m2_t tmp = vfwcvt_f_f_v_f32m2(fp16, GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)); GiSetSubVectorFloat32V2(ret, 0, vget_v_f32m2_f32m1(tmp, 0)); GiSetSubVectorFloat32V2(ret, 1, vget_v_f32m2_f32m1(tmp, 1)); return ret; #endif } GI_FORCEINLINE GI_FLOAT16_t GiCastFloat32ToFloat16(const GI_FLOAT32_t& low, const GI_FLOAT32_t& high) { #if defined(GI_NEON_INTRINSICS) return vcombine_f16(vcvt_f16_f32(low), vcvt_f16_f32(high)); #elif defined(GI_RVV_INTRINSICS) vfloat32m2_t tmp = vfmv_v_f_f32m2(0.0, GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)); tmp = vset_v_f32m1_f32m2(tmp, 0, low); tmp = vset_v_f32m1_f32m2(tmp, 1, high); return vfncvt_f_f_w_f16m1(tmp, GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)); #endif } GI_FORCEINLINE GI_FLOAT16_t GiZeroFloat16(void) { return GiBroadcastFloat16(0.0); } GI_FORCEINLINE GI_FLOAT16_t GiLoadFloat16(const gi_float16_t* Buffer) { #if defined(GI_NEON_INTRINSICS) return vld1q_f16(Buffer); #elif defined(GI_RVV_INTRINSICS) return vle16_v_f16m1(Buffer, GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)); #endif } // !return a + b * c GI_FORCEINLINE GI_FLOAT16_t GiMlaqFloat16(GI_FLOAT16_t a, GI_FLOAT16_t b, GI_FLOAT16_t c) { #if defined(GI_NEON_INTRINSICS) #if defined(__ARM_FEATURE_FMA) return vfmaq_f16(a, b, c); #else return vaddq_f16(a, vmulq_f16(b, c)); #endif #elif defined(GI_RVV_INTRINSICS) return vfmadd_vv_f16m1(b, c, a, GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)); #endif } GI_FORCEINLINE void GiStoreFloat16(gi_float16_t* Buffer, GI_FLOAT16_t Vector) { #if defined(GI_NEON_INTRINSICS) vst1q_f16(Buffer, Vector); #elif defined(GI_RVV_INTRINSICS) vse16_v_f16m1(Buffer, Vector, GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)); #endif } GI_FORCEINLINE GI_FLOAT16_t GiAddFloat16(GI_FLOAT16_t Vector1, GI_FLOAT16_t Vector2) { #if defined(GI_NEON_INTRINSICS) return vaddq_f16(Vector1, Vector2); #elif defined(GI_RVV_INTRINSICS) return vfadd_vv_f16m1(Vector1, Vector2, GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)); #endif } GI_FORCEINLINE GI_FLOAT16_t GiSubtractFloat16(GI_FLOAT16_t Vector1, GI_FLOAT16_t Vector2) { #if defined(GI_NEON_INTRINSICS) return vsubq_f16(Vector1, Vector2); #elif defined(GI_RVV_INTRINSICS) return vfsub_vv_f16m1(Vector1, Vector2, GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)); #endif } GI_FORCEINLINE GI_FLOAT16_t GiMultiplyFloat16(GI_FLOAT16_t Vector1, GI_FLOAT16_t Vector2) { #if defined(GI_NEON_INTRINSICS) return vmulq_f16(Vector1, Vector2); #elif defined(GI_RVV_INTRINSICS) return vfmul_vv_f16m1(Vector1, Vector2, GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)); #endif } GI_FORCEINLINE GI_FLOAT16_t GiMultiplyScalerFloat16(GI_FLOAT16_t Vector1, gi_float16_t Scaler) { #if defined(GI_NEON_INTRINSICS) return vmulq_n_f16(Vector1, Scaler); #elif defined(GI_RVV_INTRINSICS) return vfmul_vf_f16m1(Vector1, Scaler, GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)); #endif } GI_FORCEINLINE GI_FLOAT16_t GiMultiplyAddScalarFloat16( GI_FLOAT16_t VectorSum, GI_FLOAT16_t Vector, gi_float16_t Scalar) { #if defined(GI_NEON_INTRINSICS) return v_fma_n_f16(VectorSum, Vector, Scalar); #elif defined(GI_RVV_INTRINSICS) return vfmadd_vf_f16m1( Vector, Scalar, VectorSum, GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)); #endif } GI_FORCEINLINE GI_FLOAT16_t GiMultiplySubScalarFloat16( GI_FLOAT16_t VectorSub, GI_FLOAT16_t Vector, gi_float16_t Scalar) { #if defined(GI_NEON_INTRINSICS) return vsubq_f16(VectorSub, vmulq_n_f16(Vector, Scalar)); #elif defined(GI_RVV_INTRINSICS) return vfnmsub_vf_f16m1( Vector, Scalar, VectorSub, GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)); #endif } GI_FORCEINLINE GI_FLOAT16_t GiMaximumFloat16(GI_FLOAT16_t Vector1, GI_FLOAT16_t Vector2) { #if defined(GI_NEON_INTRINSICS) return vmaxq_f16(Vector1, Vector2); #elif defined(GI_RVV_INTRINSICS) return vfmax_vv_f16m1(Vector1, Vector2, GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)); #endif } GI_FORCEINLINE GI_FLOAT16_t GiMinimumFloat16(GI_FLOAT16_t Vector1, GI_FLOAT16_t Vector2) { #if defined(GI_NEON_INTRINSICS) return vminq_f16(Vector1, Vector2); #elif defined(GI_RVV_INTRINSICS) return vfmin_vv_f16m1(Vector1, Vector2, GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)); #endif } //! a + b * c[d] #if defined(GI_NEON_INTRINSICS) #define GiSimdFmaLaneFloat16(a, b, c, d) vfmaq_laneq_f16(a, b, c, d) #elif defined(GI_RVV_INTRINSICS) #define __rvv_fmaq_laneq_f16(__a, __b, __c, __lane) \ __extension__({ \ gi_float16_t t[GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)]; \ vse16_v_f16m1(t, __c, GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)); \ GI_FLOAT16_t __ret = vfmadd_vf_f16m1( \ __b, t[__lane], __a, GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)); \ __ret; \ }) #define GiSimdFmaLaneFloat16(a, b, c, d) __rvv_fmaq_laneq_f16(a, b, c, d) #endif //! a - b * v[lane] #if defined(GI_NEON_INTRINSICS) #define GiFmsqLaneQFloat16(a, b, v, lane) vfmsq_laneq_f16(a, b, v, lane) #elif defined(GI_RVV_INTRINSICS) #define __rvv_fmsq_lane_float16(__a, __b, __c, __lane) \ __extension__({ \ gi_float16_t t[GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)]; \ vse16_v_f16m1(t, __c, GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)); \ GI_FLOAT16_t __ret = vfnmsub_vf_f16m1( \ __b, t[__lane], __a, GI_SIMD_LEN_BYTE / sizeof(gi_float16_t)); \ __ret; \ }) #define GiFmsqLaneQFloat16(a, b, c, d) __rvv_fmsq_lane_float16(a, b, c, d) #endif #endif