GCC Code Coverage Report


Directory: src/
File: src/types/vec16.c
Date: 2026-09-30 11:11:31
Exec Total Coverage
Lines: 40 43 93.0%
Functions: 6 6 100.0%
Branches: 17 22 77.3%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2026 Tiger Data, Inc.
3 * Licensed under the PostgreSQL License. See LICENSE for details.
4 *
5 * vec16.c - Half-precision vector operations and type dispatch
6 *
7 * Implements:
8 * - Bulk half<->float conversion with SIMD dispatch
9 * - Vec32TypeOps for float32 (zero-copy wrappers)
10 * - Vec32TypeOps for float16 (convert-in-register distance)
11 * - Vec16 lifecycle
12 */
13
14 #include "vs_config.h"
15
16 #include <string.h>
17
18 #include "core/memory.h"
19 #include "types/vec16.h"
20 #include "types/vec32.h"
21
22 /* ----------------------------------------------------------------
23 * Bulk conversion
24 *
25 * On x86 with F16C: _mm256_cvtph_ps / _mm256_cvtps_ph (8 at a time)
26 * On ARM with FP16: vcvt_f32_f16 / vcvt_f16_f32 (4 at a time)
27 * Fallback: scalar loop via vs_half_to_float / vs_float_to_half
28 * ---------------------------------------------------------------- */
29
30 #if defined(VS_F16C_SUPPORT) && !defined(VS_SIMD_NONE)
31
32 __attribute__((target("avx,f16c"))) void
33 25904 vs_half_to_float_array(const half *src, float *dst, uint32_t n)
34 {
35 25904 uint32_t i = 0;
36
2/2
✓ Branch 0 taken 28521 times.
✓ Branch 1 taken 25904 times.
54425 for (; i + 8 <= n; i += 8)
37 {
38 38735 __m128i h8 = _mm_loadu_si128((const __m128i *)(src + i));
39 28521 __m256 f8 = _mm256_cvtph_ps(h8);
40 28521 _mm256_storeu_ps(dst + i, f8);
41 }
42
2/2
✓ Branch 0 taken 33909 times.
✓ Branch 1 taken 25904 times.
59813 for (; i < n; i++)
43 33909 dst[i] = vs_half_to_float(src[i]);
44 25904 }
45
46 __attribute__((target("avx,f16c"))) void
47 4585 vs_float_to_half_array(const float *src, half *dst, uint32_t n)
48 {
49 4585 uint32_t i = 0;
50
2/2
✓ Branch 0 taken 10576 times.
✓ Branch 1 taken 4585 times.
15161 for (; i + 8 <= n; i += 8)
51 {
52 10576 __m256 f8 = _mm256_loadu_ps(src + i);
53 10576 __m128i h8 = _mm256_cvtps_ph(
54 f8, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
55 10576 _mm_storeu_si128((__m128i *)(dst + i), h8);
56 }
57
2/2
✓ Branch 0 taken 6739 times.
✓ Branch 1 taken 4585 times.
11324 for (; i < n; i++)
58 6739 dst[i] = vs_float_to_half(src[i]);
59 4585 }
60
61 #elif defined(__aarch64__) && defined(__ARM_FP16_FORMAT_IEEE) && \
62 !defined(VS_SIMD_NONE)
63
64 #include <arm_neon.h>
65
66 void
67 vs_half_to_float_array(const half *src, float *dst, uint32_t n)
68 {
69 uint32_t i = 0;
70 for (; i + 4 <= n; i += 4)
71 {
72 float16x4_t h4 = vld1_f16((const float16_t *)(src + i));
73 float32x4_t f4 = vcvt_f32_f16(h4);
74 vst1q_f32(dst + i, f4);
75 }
76 for (; i < n; i++)
77 dst[i] = vs_half_to_float(src[i]);
78 }
79
80 void
81 vs_float_to_half_array(const float *src, half *dst, uint32_t n)
82 {
83 uint32_t i = 0;
84 for (; i + 4 <= n; i += 4)
85 {
86 float32x4_t f4 = vld1q_f32(src + i);
87 float16x4_t h4 = vcvt_f16_f32(f4);
88 vst1_f16((float16_t *)(dst + i), h4);
89 }
90 for (; i < n; i++)
91 dst[i] = vs_float_to_half(src[i]);
92 }
93
94 #else
95
96 /* Scalar fallback */
97 void
98 vs_half_to_float_array(const half *src, float *dst, uint32_t n)
99 {
100 for (uint32_t i = 0; i < n; i++)
101 dst[i] = vs_half_to_float(src[i]);
102 }
103
104 void
105 vs_float_to_half_array(const float *src, half *dst, uint32_t n)
106 {
107 for (uint32_t i = 0; i < n; i++)
108 dst[i] = vs_float_to_half(src[i]);
109 }
110
111 #endif
112
113 /* ----------------------------------------------------------------
114 * Vec16 lifecycle
115 * ---------------------------------------------------------------- */
116
117 Vec16 *
118 10 vec16_create(Dimension dim)
119 {
120
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
10 if (dim == 0 || dim > VEC32_MAX_DIM)
121 2 return NULL;
122
123 8 size_t size = VEC16_SIZE(dim);
124 8 Vec16 *v = vs_alloc0(size);
125
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (v == NULL)
126 ✗ return NULL;
127
128 8 VS_SET_VARSIZE(v, size);
129 8 v->dim = (int16_t)dim;
130 8 return v;
131 }
132
133 Vec16 *
134 6 vec16_from_floats(const float *values, Dimension dim)
135 {
136
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 if (values == NULL)
137 2 return NULL;
138
139 4 Vec16 *v = vec16_create(dim);
140
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (v == NULL)
141 ✗ return NULL;
142
143 4 vs_float_to_half_array(values, v->x, dim);
144 4 return v;
145 }
146
147 void
148 8 vec16_free(Vec16 *v)
149 {
150 8 vs_free(v);
151 8 }
152
153 void
154 2 vec16_set(Vec16 *v, const float *values)
155 {
156
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if (v == NULL || values == NULL)
157 ✗ return;
158 2 vs_float_to_half_array(values, v->x, v->dim);
159 }
160