comparison src/impl/fallback.c @ 23:e26874655738

*: huge refactor, new major release (hahaha) I keep finding things that are broken... The problem NOW was that vec would unintentionally build some functions with extended instruction sets, which is Bad and would mean that for all intents and purposes the CPU detection was completely broken. Now vec is no longer header only either. Boohoo. However this gives a lot more flexibility to vec since we no longer want or need to care about C++ crap. The NEON and Altivec implementations have not been updated which means they won't compile hence why they're commented out in the cmake build file.
author Paper <paper@tflc.us>
date Sun, 24 Nov 2024 02:52:40 -0500
parents
children e49e70f7012f
comparison
equal deleted inserted replaced
22:fbcd3fa6f8fc 23:e26874655738
1 #include "vec/impl/fallback.h"
2
3 #include <string.h>
4
5 // Fallback implementations - this is what an implementation should use if it
6 // doesn't support a specific function *and* the actual representation in
7 // memory is unknown or yields incorrect results from the generic functions.
8 // This is *extremely* unlikely; for x86 the layout is exactly the same in
9 // memory as the generic functions (i.e. it is literally stored as an array of
10 // integers).
11 //
12 // These functions can probably be removed if every current implementation is
13 // found to have the same
14
15 #define VEC_FALLBACK_OPERATION(op, sign, csign, bits, size) \
16 do { \
17 V##csign##INT##bits##x##size##_ALIGNED_ARRAY(varr1); \
18 V##csign##INT##bits##x##size##_ALIGNED_ARRAY(varr2); \
19 \
20 v##sign##int##bits##x##size##_store_aligned(vec1, varr1); \
21 v##sign##int##bits##x##size##_store_aligned(vec2, varr2); \
22 \
23 for (int i = 0; i < size; i++) varr1[i] = (op); \
24 \
25 return v##sign##int##bits##x##size##_load_aligned(varr1); \
26 } while (0)
27
28 #define VEC_FALLBACK_CMP(op, sign, csign, bits, size) \
29 VEC_FALLBACK_OPERATION((varr1[i] op varr2[i]) ? VEC_UINT##bits##_MAX : 0, sign, csign, bits, size)
30
31 #define VEC_FALLBACK_SHIFT(op, sign, csign, bits, size) \
32 do { \
33 V##csign##INT##bits##x##size##_ALIGNED_ARRAY(varr1); \
34 VUINT##bits##x##size##_ALIGNED_ARRAY(varr2); \
35 \
36 v##sign##int##bits##x##size##_store_aligned(vec1, varr1); \
37 vuint##bits##x##size##_store_aligned(vec2, varr2); \
38 \
39 for (int i = 0; i < size; i++) varr1[i] = (op); \
40 \
41 return v##sign##int##bits##x##size##_load_aligned(varr1); \
42 } while (0)
43
44 #define VEC_DEFINE_FALLBACK_OPERATIONS_SIGN(sign, csign, bits, size) \
45 v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_splat(vec_##sign##int##bits x) \
46 { \
47 V##csign##INT##bits##x##size##_ALIGNED_ARRAY(arr); \
48 for (int i = 0; i < size; i++) arr[i] = x; \
49 return v##sign##int##bits##x##size##_load_aligned(arr); \
50 } \
51 \
52 v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_load(const vec_##sign##int##bits in[size]) \
53 { \
54 V##csign##INT##bits##x##size##_ALIGNED_ARRAY(arr); \
55 memcpy(arr, in, sizeof(vec_##sign##int##bits) * size); \
56 return v##sign##int##bits##x##size##_load_aligned(arr); \
57 } \
58 \
59 void v##sign##int##bits##x##size##_fallback_store(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \
60 { \
61 V##csign##INT##bits##x##size##_ALIGNED_ARRAY(arr); \
62 v##sign##int##bits##x##size##_store_aligned(vec, arr); \
63 memcpy(out, arr, sizeof(vec_##sign##int##bits) * size); \
64 } \
65 \
66 v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
67 { \
68 VEC_FALLBACK_OPERATION(varr1[i] + varr2[i], sign, csign, bits, size); \
69 } \
70 \
71 v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
72 { \
73 VEC_FALLBACK_OPERATION(varr1[i] - varr2[i], sign, csign, bits, size); \
74 } \
75 \
76 v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
77 { \
78 VEC_FALLBACK_OPERATION(varr1[i] * varr2[i], sign, csign, bits, size); \
79 } \
80 \
81 v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_div(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
82 { \
83 VEC_FALLBACK_OPERATION(varr2[i] ? (varr1[i] / varr2[i]) : 0, sign, csign, bits, size); \
84 } \
85 \
86 v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_avg(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
87 { \
88 VEC_FALLBACK_OPERATION((varr1[i] + varr2[i] + 1) / 2, sign, csign, bits, size); \
89 } \
90 \
91 v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
92 { \
93 VEC_FALLBACK_OPERATION(varr1[i] & varr2[i], sign, csign, bits, size); \
94 } \
95 \
96 v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
97 { \
98 VEC_FALLBACK_OPERATION(varr1[i] | varr2[i], sign, csign, bits, size); \
99 } \
100 \
101 v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
102 { \
103 VEC_FALLBACK_OPERATION(varr1[i] ^ varr2[i], sign, csign, bits, size); \
104 } \
105 \
106 v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_not(v##sign##int##bits##x##size vec) \
107 { \
108 return v##sign##int##bits##x##size##_xor(vec, v##sign##int##bits##x##size##_splat((vec_##sign##int##bits)VEC_UINT##bits##_MAX)); \
109 } \
110 \
111 v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_cmplt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
112 { \
113 VEC_FALLBACK_CMP(<, sign, csign, bits, size); \
114 } \
115 \
116 v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_cmple(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
117 { \
118 VEC_FALLBACK_CMP(<=, sign, csign, bits, size); \
119 } \
120 \
121 v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_cmpeq(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
122 { \
123 VEC_FALLBACK_CMP(==, sign, csign, bits, size); \
124 } \
125 \
126 v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_cmpge(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
127 { \
128 VEC_FALLBACK_CMP(>=, sign, csign, bits, size); \
129 } \
130 \
131 v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_cmpgt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
132 { \
133 VEC_FALLBACK_CMP(>, sign, csign, bits, size); \
134 } \
135 \
136 v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \
137 { \
138 VEC_FALLBACK_SHIFT(vec_##sign##lshift(varr1[i], varr2[i]), sign, csign, bits, size); \
139 } \
140 \
141 v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_rshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \
142 { \
143 VEC_FALLBACK_SHIFT(vec_##sign##rshift(varr1[i], varr2[i]), sign, csign, bits, size); \
144 } \
145 \
146 v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_lrshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \
147 { \
148 VEC_FALLBACK_SHIFT(vec_lrshift((vec_uint##bits)varr1[i], varr2[i]), sign, csign, bits, size); \
149 }
150
151 #define VEC_DEFINE_FALLBACK_OPERATIONS(bits, size) \
152 VEC_DEFINE_FALLBACK_OPERATIONS_SIGN( , , bits, size) \
153 VEC_DEFINE_FALLBACK_OPERATIONS_SIGN(u, U, bits, size)
154
155 // 16-bit
156 VEC_DEFINE_FALLBACK_OPERATIONS(8, 2)
157
158 // 32-bit
159 VEC_DEFINE_FALLBACK_OPERATIONS(8, 4)
160 VEC_DEFINE_FALLBACK_OPERATIONS(16, 2)
161
162 // 64-bit
163 VEC_DEFINE_FALLBACK_OPERATIONS(8, 8)
164 VEC_DEFINE_FALLBACK_OPERATIONS(16, 4)
165 VEC_DEFINE_FALLBACK_OPERATIONS(32, 2)
166
167 // 128-bit
168 VEC_DEFINE_FALLBACK_OPERATIONS(8, 16)
169 VEC_DEFINE_FALLBACK_OPERATIONS(16, 8)
170 VEC_DEFINE_FALLBACK_OPERATIONS(32, 4)
171 VEC_DEFINE_FALLBACK_OPERATIONS(64, 2)
172
173 // 256-bit
174 VEC_DEFINE_FALLBACK_OPERATIONS(8, 32)
175 VEC_DEFINE_FALLBACK_OPERATIONS(16, 16)
176 VEC_DEFINE_FALLBACK_OPERATIONS(32, 8)
177 VEC_DEFINE_FALLBACK_OPERATIONS(64, 4)
178
179 // 512-bit
180 VEC_DEFINE_FALLBACK_OPERATIONS(8, 64)
181 VEC_DEFINE_FALLBACK_OPERATIONS(16, 32)
182 VEC_DEFINE_FALLBACK_OPERATIONS(32, 16)
183 VEC_DEFINE_FALLBACK_OPERATIONS(64, 8)
184
185 #undef VEC_FALLBACK_OPERATION
186 #undef VEC_FALLBACK_CMP
187 #undef VEC_FALLBACK_SHIFT
188 #undef VEC_DEFINE_FALLBACK_OPERATIONS
189 #undef VEC_DEFINE_FALLBACK_OPERATIONS_SIGN