btVector3.cpp 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665
  1. /*
  2. Copyright (c) 2011 Apple Inc.
  3. https://bulletphysics.org
  4. This software is provided 'as-is', without any express or implied warranty.
  5. In no event will the authors be held liable for any damages arising from the use of this software.
  6. Permission is granted to anyone to use this software for any purpose,
  7. including commercial applications, and to alter it and redistribute it freely,
  8. subject to the following restrictions:
  9. 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
  10. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  11. 3. This notice may not be removed or altered from any source distribution.
  12. This source version has been altered.
  13. */
  14. #if defined(_WIN32) || defined(__i386__)
  15. #define BT_USE_SSE_IN_API
  16. #endif
  17. #include "btVector3.h"
  18. #if defined BT_USE_SIMD_VECTOR3
  19. #if DEBUG
  20. #include <string.h> //for memset
  21. #endif
  22. #ifdef __APPLE__
  23. #include <stdint.h>
  24. typedef float float4 __attribute__((vector_size(16)));
  25. #else
  26. #define float4 __m128
  27. #endif
  28. //typedef uint32_t uint4 __attribute__ ((vector_size(16)));
  29. #if defined BT_USE_SSE || defined _WIN32
  30. #define LOG2_ARRAY_SIZE 6
  31. #define STACK_ARRAY_COUNT (1UL << LOG2_ARRAY_SIZE)
  32. #include <emmintrin.h>
  33. long _maxdot_large(const float *vv, const float *vec, unsigned long count, float *dotResult);
  34. long _maxdot_large(const float *vv, const float *vec, unsigned long count, float *dotResult)
  35. {
  36. const float4 *vertices = (const float4 *)vv;
  37. static const unsigned char indexTable[16] = {(unsigned char)-1, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0};
  38. float4 dotMax = btAssign128(-BT_INFINITY, -BT_INFINITY, -BT_INFINITY, -BT_INFINITY);
  39. float4 vvec = _mm_loadu_ps(vec);
  40. float4 vHi = btCastiTo128f(_mm_shuffle_epi32(btCastfTo128i(vvec), 0xaa)); /// zzzz
  41. float4 vLo = _mm_movelh_ps(vvec, vvec); /// xyxy
  42. long maxIndex = -1L;
  43. size_t segment = 0;
  44. float4 stack_array[STACK_ARRAY_COUNT];
  45. #if DEBUG
  46. //memset( stack_array, -1, STACK_ARRAY_COUNT * sizeof(stack_array[0]) );
  47. #endif
  48. size_t index;
  49. float4 max;
  50. // Faster loop without cleanup code for full tiles
  51. for (segment = 0; segment + STACK_ARRAY_COUNT * 4 <= count; segment += STACK_ARRAY_COUNT * 4)
  52. {
  53. max = dotMax;
  54. for (index = 0; index < STACK_ARRAY_COUNT; index += 4)
  55. { // do four dot products at a time. Carefully avoid touching the w element.
  56. float4 v0 = vertices[0];
  57. float4 v1 = vertices[1];
  58. float4 v2 = vertices[2];
  59. float4 v3 = vertices[3];
  60. vertices += 4;
  61. float4 lo0 = _mm_movelh_ps(v0, v1); // x0y0x1y1
  62. float4 hi0 = _mm_movehl_ps(v1, v0); // z0?0z1?1
  63. float4 lo1 = _mm_movelh_ps(v2, v3); // x2y2x3y3
  64. float4 hi1 = _mm_movehl_ps(v3, v2); // z2?2z3?3
  65. lo0 = lo0 * vLo;
  66. lo1 = lo1 * vLo;
  67. float4 z = _mm_shuffle_ps(hi0, hi1, 0x88);
  68. float4 x = _mm_shuffle_ps(lo0, lo1, 0x88);
  69. float4 y = _mm_shuffle_ps(lo0, lo1, 0xdd);
  70. z = z * vHi;
  71. x = x + y;
  72. x = x + z;
  73. stack_array[index] = x;
  74. max = _mm_max_ps(x, max); // control the order here so that max is never NaN even if x is nan
  75. v0 = vertices[0];
  76. v1 = vertices[1];
  77. v2 = vertices[2];
  78. v3 = vertices[3];
  79. vertices += 4;
  80. lo0 = _mm_movelh_ps(v0, v1); // x0y0x1y1
  81. hi0 = _mm_movehl_ps(v1, v0); // z0?0z1?1
  82. lo1 = _mm_movelh_ps(v2, v3); // x2y2x3y3
  83. hi1 = _mm_movehl_ps(v3, v2); // z2?2z3?3
  84. lo0 = lo0 * vLo;
  85. lo1 = lo1 * vLo;
  86. z = _mm_shuffle_ps(hi0, hi1, 0x88);
  87. x = _mm_shuffle_ps(lo0, lo1, 0x88);
  88. y = _mm_shuffle_ps(lo0, lo1, 0xdd);
  89. z = z * vHi;
  90. x = x + y;
  91. x = x + z;
  92. stack_array[index + 1] = x;
  93. max = _mm_max_ps(x, max); // control the order here so that max is never NaN even if x is nan
  94. v0 = vertices[0];
  95. v1 = vertices[1];
  96. v2 = vertices[2];
  97. v3 = vertices[3];
  98. vertices += 4;
  99. lo0 = _mm_movelh_ps(v0, v1); // x0y0x1y1
  100. hi0 = _mm_movehl_ps(v1, v0); // z0?0z1?1
  101. lo1 = _mm_movelh_ps(v2, v3); // x2y2x3y3
  102. hi1 = _mm_movehl_ps(v3, v2); // z2?2z3?3
  103. lo0 = lo0 * vLo;
  104. lo1 = lo1 * vLo;
  105. z = _mm_shuffle_ps(hi0, hi1, 0x88);
  106. x = _mm_shuffle_ps(lo0, lo1, 0x88);
  107. y = _mm_shuffle_ps(lo0, lo1, 0xdd);
  108. z = z * vHi;
  109. x = x + y;
  110. x = x + z;
  111. stack_array[index + 2] = x;
  112. max = _mm_max_ps(x, max); // control the order here so that max is never NaN even if x is nan
  113. v0 = vertices[0];
  114. v1 = vertices[1];
  115. v2 = vertices[2];
  116. v3 = vertices[3];
  117. vertices += 4;
  118. lo0 = _mm_movelh_ps(v0, v1); // x0y0x1y1
  119. hi0 = _mm_movehl_ps(v1, v0); // z0?0z1?1
  120. lo1 = _mm_movelh_ps(v2, v3); // x2y2x3y3
  121. hi1 = _mm_movehl_ps(v3, v2); // z2?2z3?3
  122. lo0 = lo0 * vLo;
  123. lo1 = lo1 * vLo;
  124. z = _mm_shuffle_ps(hi0, hi1, 0x88);
  125. x = _mm_shuffle_ps(lo0, lo1, 0x88);
  126. y = _mm_shuffle_ps(lo0, lo1, 0xdd);
  127. z = z * vHi;
  128. x = x + y;
  129. x = x + z;
  130. stack_array[index + 3] = x;
  131. max = _mm_max_ps(x, max); // control the order here so that max is never NaN even if x is nan
  132. // It is too costly to keep the index of the max here. We will look for it again later. We save a lot of work this way.
  133. }
  134. // If we found a new max
  135. if (0xf != _mm_movemask_ps((float4)_mm_cmpeq_ps(max, dotMax)))
  136. {
  137. // copy the new max across all lanes of our max accumulator
  138. max = _mm_max_ps(max, (float4)_mm_shuffle_ps(max, max, 0x4e));
  139. max = _mm_max_ps(max, (float4)_mm_shuffle_ps(max, max, 0xb1));
  140. dotMax = max;
  141. // find first occurrence of that max
  142. size_t test;
  143. for (index = 0; 0 == (test = _mm_movemask_ps(_mm_cmpeq_ps(stack_array[index], max))); index++) // local_count must be a multiple of 4
  144. {
  145. }
  146. // record where it is.
  147. maxIndex = 4 * index + segment + indexTable[test];
  148. }
  149. }
  150. // account for work we've already done
  151. count -= segment;
  152. // Deal with the last < STACK_ARRAY_COUNT vectors
  153. max = dotMax;
  154. index = 0;
  155. if (btUnlikely(count > 16))
  156. {
  157. for (; index + 4 <= count / 4; index += 4)
  158. { // do four dot products at a time. Carefully avoid touching the w element.
  159. float4 v0 = vertices[0];
  160. float4 v1 = vertices[1];
  161. float4 v2 = vertices[2];
  162. float4 v3 = vertices[3];
  163. vertices += 4;
  164. float4 lo0 = _mm_movelh_ps(v0, v1); // x0y0x1y1
  165. float4 hi0 = _mm_movehl_ps(v1, v0); // z0?0z1?1
  166. float4 lo1 = _mm_movelh_ps(v2, v3); // x2y2x3y3
  167. float4 hi1 = _mm_movehl_ps(v3, v2); // z2?2z3?3
  168. lo0 = lo0 * vLo;
  169. lo1 = lo1 * vLo;
  170. float4 z = _mm_shuffle_ps(hi0, hi1, 0x88);
  171. float4 x = _mm_shuffle_ps(lo0, lo1, 0x88);
  172. float4 y = _mm_shuffle_ps(lo0, lo1, 0xdd);
  173. z = z * vHi;
  174. x = x + y;
  175. x = x + z;
  176. stack_array[index] = x;
  177. max = _mm_max_ps(x, max); // control the order here so that max is never NaN even if x is nan
  178. v0 = vertices[0];
  179. v1 = vertices[1];
  180. v2 = vertices[2];
  181. v3 = vertices[3];
  182. vertices += 4;
  183. lo0 = _mm_movelh_ps(v0, v1); // x0y0x1y1
  184. hi0 = _mm_movehl_ps(v1, v0); // z0?0z1?1
  185. lo1 = _mm_movelh_ps(v2, v3); // x2y2x3y3
  186. hi1 = _mm_movehl_ps(v3, v2); // z2?2z3?3
  187. lo0 = lo0 * vLo;
  188. lo1 = lo1 * vLo;
  189. z = _mm_shuffle_ps(hi0, hi1, 0x88);
  190. x = _mm_shuffle_ps(lo0, lo1, 0x88);
  191. y = _mm_shuffle_ps(lo0, lo1, 0xdd);
  192. z = z * vHi;
  193. x = x + y;
  194. x = x + z;
  195. stack_array[index + 1] = x;
  196. max = _mm_max_ps(x, max); // control the order here so that max is never NaN even if x is nan
  197. v0 = vertices[0];
  198. v1 = vertices[1];
  199. v2 = vertices[2];
  200. v3 = vertices[3];
  201. vertices += 4;
  202. lo0 = _mm_movelh_ps(v0, v1); // x0y0x1y1
  203. hi0 = _mm_movehl_ps(v1, v0); // z0?0z1?1
  204. lo1 = _mm_movelh_ps(v2, v3); // x2y2x3y3
  205. hi1 = _mm_movehl_ps(v3, v2); // z2?2z3?3
  206. lo0 = lo0 * vLo;
  207. lo1 = lo1 * vLo;
  208. z = _mm_shuffle_ps(hi0, hi1, 0x88);
  209. x = _mm_shuffle_ps(lo0, lo1, 0x88);
  210. y = _mm_shuffle_ps(lo0, lo1, 0xdd);
  211. z = z * vHi;
  212. x = x + y;
  213. x = x + z;
  214. stack_array[index + 2] = x;
  215. max = _mm_max_ps(x, max); // control the order here so that max is never NaN even if x is nan
  216. v0 = vertices[0];
  217. v1 = vertices[1];
  218. v2 = vertices[2];
  219. v3 = vertices[3];
  220. vertices += 4;
  221. lo0 = _mm_movelh_ps(v0, v1); // x0y0x1y1
  222. hi0 = _mm_movehl_ps(v1, v0); // z0?0z1?1
  223. lo1 = _mm_movelh_ps(v2, v3); // x2y2x3y3
  224. hi1 = _mm_movehl_ps(v3, v2); // z2?2z3?3
  225. lo0 = lo0 * vLo;
  226. lo1 = lo1 * vLo;
  227. z = _mm_shuffle_ps(hi0, hi1, 0x88);
  228. x = _mm_shuffle_ps(lo0, lo1, 0x88);
  229. y = _mm_shuffle_ps(lo0, lo1, 0xdd);
  230. z = z * vHi;
  231. x = x + y;
  232. x = x + z;
  233. stack_array[index + 3] = x;
  234. max = _mm_max_ps(x, max); // control the order here so that max is never NaN even if x is nan
  235. // It is too costly to keep the index of the max here. We will look for it again later. We save a lot of work this way.
  236. }
  237. }
  238. size_t localCount = (count & -4L) - 4 * index;
  239. if (localCount)
  240. {
  241. #ifdef __APPLE__
  242. float4 t0, t1, t2, t3, t4;
  243. float4 *sap = &stack_array[index + localCount / 4];
  244. vertices += localCount; // counter the offset
  245. size_t byteIndex = -(localCount) * sizeof(float);
  246. //AT&T Code style assembly
  247. asm volatile(
  248. ".align 4 \n\
  249. 0: movaps %[max], %[t2] // move max out of the way to avoid propagating NaNs in max \n\
  250. movaps (%[vertices], %[byteIndex], 4), %[t0] // vertices[0] \n\
  251. movaps 16(%[vertices], %[byteIndex], 4), %[t1] // vertices[1] \n\
  252. movaps %[t0], %[max] // vertices[0] \n\
  253. movlhps %[t1], %[max] // x0y0x1y1 \n\
  254. movaps 32(%[vertices], %[byteIndex], 4), %[t3] // vertices[2] \n\
  255. movaps 48(%[vertices], %[byteIndex], 4), %[t4] // vertices[3] \n\
  256. mulps %[vLo], %[max] // x0y0x1y1 * vLo \n\
  257. movhlps %[t0], %[t1] // z0w0z1w1 \n\
  258. movaps %[t3], %[t0] // vertices[2] \n\
  259. movlhps %[t4], %[t0] // x2y2x3y3 \n\
  260. mulps %[vLo], %[t0] // x2y2x3y3 * vLo \n\
  261. movhlps %[t3], %[t4] // z2w2z3w3 \n\
  262. shufps $0x88, %[t4], %[t1] // z0z1z2z3 \n\
  263. mulps %[vHi], %[t1] // z0z1z2z3 * vHi \n\
  264. movaps %[max], %[t3] // x0y0x1y1 * vLo \n\
  265. shufps $0x88, %[t0], %[max] // x0x1x2x3 * vLo.x \n\
  266. shufps $0xdd, %[t0], %[t3] // y0y1y2y3 * vLo.y \n\
  267. addps %[t3], %[max] // x + y \n\
  268. addps %[t1], %[max] // x + y + z \n\
  269. movaps %[max], (%[sap], %[byteIndex]) // record result for later scrutiny \n\
  270. maxps %[t2], %[max] // record max, restore max \n\
  271. add $16, %[byteIndex] // advance loop counter\n\
  272. jnz 0b \n\
  273. "
  274. : [max] "+x"(max), [t0] "=&x"(t0), [t1] "=&x"(t1), [t2] "=&x"(t2), [t3] "=&x"(t3), [t4] "=&x"(t4), [byteIndex] "+r"(byteIndex)
  275. : [vLo] "x"(vLo), [vHi] "x"(vHi), [vertices] "r"(vertices), [sap] "r"(sap)
  276. : "memory", "cc");
  277. index += localCount / 4;
  278. #else
  279. {
  280. for (unsigned int i = 0; i < localCount / 4; i++, index++)
  281. { // do four dot products at a time. Carefully avoid touching the w element.
  282. float4 v0 = vertices[0];
  283. float4 v1 = vertices[1];
  284. float4 v2 = vertices[2];
  285. float4 v3 = vertices[3];
  286. vertices += 4;
  287. float4 lo0 = _mm_movelh_ps(v0, v1); // x0y0x1y1
  288. float4 hi0 = _mm_movehl_ps(v1, v0); // z0?0z1?1
  289. float4 lo1 = _mm_movelh_ps(v2, v3); // x2y2x3y3
  290. float4 hi1 = _mm_movehl_ps(v3, v2); // z2?2z3?3
  291. lo0 = lo0 * vLo;
  292. lo1 = lo1 * vLo;
  293. float4 z = _mm_shuffle_ps(hi0, hi1, 0x88);
  294. float4 x = _mm_shuffle_ps(lo0, lo1, 0x88);
  295. float4 y = _mm_shuffle_ps(lo0, lo1, 0xdd);
  296. z = z * vHi;
  297. x = x + y;
  298. x = x + z;
  299. stack_array[index] = x;
  300. max = _mm_max_ps(x, max); // control the order here so that max is never NaN even if x is nan
  301. }
  302. }
  303. #endif //__APPLE__
  304. }
  305. // process the last few points
  306. if (count & 3)
  307. {
  308. float4 v0, v1, v2, x, y, z;
  309. switch (count & 3)
  310. {
  311. case 3:
  312. {
  313. v0 = vertices[0];
  314. v1 = vertices[1];
  315. v2 = vertices[2];
  316. // Calculate 3 dot products, transpose, duplicate v2
  317. float4 lo0 = _mm_movelh_ps(v0, v1); // xyxy.lo
  318. float4 hi0 = _mm_movehl_ps(v1, v0); // z?z?.lo
  319. lo0 = lo0 * vLo;
  320. z = _mm_shuffle_ps(hi0, v2, 0xa8); // z0z1z2z2
  321. z = z * vHi;
  322. float4 lo1 = _mm_movelh_ps(v2, v2); // xyxy
  323. lo1 = lo1 * vLo;
  324. x = _mm_shuffle_ps(lo0, lo1, 0x88);
  325. y = _mm_shuffle_ps(lo0, lo1, 0xdd);
  326. }
  327. break;
  328. case 2:
  329. {
  330. v0 = vertices[0];
  331. v1 = vertices[1];
  332. float4 xy = _mm_movelh_ps(v0, v1);
  333. z = _mm_movehl_ps(v1, v0);
  334. xy = xy * vLo;
  335. z = _mm_shuffle_ps(z, z, 0xa8);
  336. x = _mm_shuffle_ps(xy, xy, 0xa8);
  337. y = _mm_shuffle_ps(xy, xy, 0xfd);
  338. z = z * vHi;
  339. }
  340. break;
  341. case 1:
  342. {
  343. float4 xy = vertices[0];
  344. z = _mm_shuffle_ps(xy, xy, 0xaa);
  345. xy = xy * vLo;
  346. z = z * vHi;
  347. x = _mm_shuffle_ps(xy, xy, 0);
  348. y = _mm_shuffle_ps(xy, xy, 0x55);
  349. }
  350. break;
  351. }
  352. x = x + y;
  353. x = x + z;
  354. stack_array[index] = x;
  355. max = _mm_max_ps(x, max); // control the order here so that max is never NaN even if x is nan
  356. index++;
  357. }
  358. // if we found a new max.
  359. if (0 == segment || 0xf != _mm_movemask_ps((float4)_mm_cmpeq_ps(max, dotMax)))
  360. { // we found a new max. Search for it
  361. // find max across the max vector, place in all elements of max -- big latency hit here
  362. max = _mm_max_ps(max, (float4)_mm_shuffle_ps(max, max, 0x4e));
  363. max = _mm_max_ps(max, (float4)_mm_shuffle_ps(max, max, 0xb1));
  364. // It is slightly faster to do this part in scalar code when count < 8. However, the common case for
  365. // this where it actually makes a difference is handled in the early out at the top of the function,
  366. // so it is less than a 1% difference here. I opted for improved code size, fewer branches and reduced
  367. // complexity, and removed it.
  368. dotMax = max;
  369. // scan for the first occurence of max in the array
  370. size_t test;
  371. for (index = 0; 0 == (test = _mm_movemask_ps(_mm_cmpeq_ps(stack_array[index], max))); index++) // local_count must be a multiple of 4
  372. {
  373. }
  374. maxIndex = 4 * index + segment + indexTable[test];
  375. }
  376. _mm_store_ss(dotResult, dotMax);
  377. return maxIndex;
  378. }
  379. long _mindot_large(const float *vv, const float *vec, unsigned long count, float *dotResult);
  380. long _mindot_large(const float *vv, const float *vec, unsigned long count, float *dotResult)
  381. {
  382. const float4 *vertices = (const float4 *)vv;
  383. static const unsigned char indexTable[16] = {(unsigned char)-1, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0};
  384. float4 dotmin = btAssign128(BT_INFINITY, BT_INFINITY, BT_INFINITY, BT_INFINITY);
  385. float4 vvec = _mm_loadu_ps(vec);
  386. float4 vHi = btCastiTo128f(_mm_shuffle_epi32(btCastfTo128i(vvec), 0xaa)); /// zzzz
  387. float4 vLo = _mm_movelh_ps(vvec, vvec); /// xyxy
  388. long minIndex = -1L;
  389. size_t segment = 0;
  390. float4 stack_array[STACK_ARRAY_COUNT];
  391. #if DEBUG
  392. //memset( stack_array, -1, STACK_ARRAY_COUNT * sizeof(stack_array[0]) );
  393. #endif
  394. size_t index;
  395. float4 min;
  396. // Faster loop without cleanup code for full tiles
  397. for (segment = 0; segment + STACK_ARRAY_COUNT * 4 <= count; segment += STACK_ARRAY_COUNT * 4)
  398. {
  399. min = dotmin;
  400. for (index = 0; index < STACK_ARRAY_COUNT; index += 4)
  401. { // do four dot products at a time. Carefully avoid touching the w element.
  402. float4 v0 = vertices[0];
  403. float4 v1 = vertices[1];
  404. float4 v2 = vertices[2];
  405. float4 v3 = vertices[3];
  406. vertices += 4;
  407. float4 lo0 = _mm_movelh_ps(v0, v1); // x0y0x1y1
  408. float4 hi0 = _mm_movehl_ps(v1, v0); // z0?0z1?1
  409. float4 lo1 = _mm_movelh_ps(v2, v3); // x2y2x3y3
  410. float4 hi1 = _mm_movehl_ps(v3, v2); // z2?2z3?3
  411. lo0 = lo0 * vLo;
  412. lo1 = lo1 * vLo;
  413. float4 z = _mm_shuffle_ps(hi0, hi1, 0x88);
  414. float4 x = _mm_shuffle_ps(lo0, lo1, 0x88);
  415. float4 y = _mm_shuffle_ps(lo0, lo1, 0xdd);
  416. z = z * vHi;
  417. x = x + y;
  418. x = x + z;
  419. stack_array[index] = x;
  420. min = _mm_min_ps(x, min); // control the order here so that min is never NaN even if x is nan
  421. v0 = vertices[0];
  422. v1 = vertices[1];
  423. v2 = vertices[2];
  424. v3 = vertices[3];
  425. vertices += 4;
  426. lo0 = _mm_movelh_ps(v0, v1); // x0y0x1y1
  427. hi0 = _mm_movehl_ps(v1, v0); // z0?0z1?1
  428. lo1 = _mm_movelh_ps(v2, v3); // x2y2x3y3
  429. hi1 = _mm_movehl_ps(v3, v2); // z2?2z3?3
  430. lo0 = lo0 * vLo;
  431. lo1 = lo1 * vLo;
  432. z = _mm_shuffle_ps(hi0, hi1, 0x88);
  433. x = _mm_shuffle_ps(lo0, lo1, 0x88);
  434. y = _mm_shuffle_ps(lo0, lo1, 0xdd);
  435. z = z * vHi;
  436. x = x + y;
  437. x = x + z;
  438. stack_array[index + 1] = x;
  439. min = _mm_min_ps(x, min); // control the order here so that min is never NaN even if x is nan
  440. v0 = vertices[0];
  441. v1 = vertices[1];
  442. v2 = vertices[2];
  443. v3 = vertices[3];
  444. vertices += 4;
  445. lo0 = _mm_movelh_ps(v0, v1); // x0y0x1y1
  446. hi0 = _mm_movehl_ps(v1, v0); // z0?0z1?1
  447. lo1 = _mm_movelh_ps(v2, v3); // x2y2x3y3
  448. hi1 = _mm_movehl_ps(v3, v2); // z2?2z3?3
  449. lo0 = lo0 * vLo;
  450. lo1 = lo1 * vLo;
  451. z = _mm_shuffle_ps(hi0, hi1, 0x88);
  452. x = _mm_shuffle_ps(lo0, lo1, 0x88);
  453. y = _mm_shuffle_ps(lo0, lo1, 0xdd);
  454. z = z * vHi;
  455. x = x + y;
  456. x = x + z;
  457. stack_array[index + 2] = x;
  458. min = _mm_min_ps(x, min); // control the order here so that min is never NaN even if x is nan
  459. v0 = vertices[0];
  460. v1 = vertices[1];
  461. v2 = vertices[2];
  462. v3 = vertices[3];
  463. vertices += 4;
  464. lo0 = _mm_movelh_ps(v0, v1); // x0y0x1y1
  465. hi0 = _mm_movehl_ps(v1, v0); // z0?0z1?1
  466. lo1 = _mm_movelh_ps(v2, v3); // x2y2x3y3
  467. hi1 = _mm_movehl_ps(v3, v2); // z2?2z3?3
  468. lo0 = lo0 * vLo;
  469. lo1 = lo1 * vLo;
  470. z = _mm_shuffle_ps(hi0, hi1, 0x88);
  471. x = _mm_shuffle_ps(lo0, lo1, 0x88);
  472. y = _mm_shuffle_ps(lo0, lo1, 0xdd);
  473. z = z * vHi;
  474. x = x + y;
  475. x = x + z;
  476. stack_array[index + 3] = x;
  477. min = _mm_min_ps(x, min); // control the order here so that min is never NaN even if x is nan
  478. // It is too costly to keep the index of the min here. We will look for it again later. We save a lot of work this way.
  479. }
  480. // If we found a new min
  481. if (0xf != _mm_movemask_ps((float4)_mm_cmpeq_ps(min, dotmin)))
  482. {
  483. // copy the new min across all lanes of our min accumulator
  484. min = _mm_min_ps(min, (float4)_mm_shuffle_ps(min, min, 0x4e));
  485. min = _mm_min_ps(min, (float4)_mm_shuffle_ps(min, min, 0xb1));
  486. dotmin = min;
  487. // find first occurrence of that min
  488. size_t test;
  489. for (index = 0; 0 == (test = _mm_movemask_ps(_mm_cmpeq_ps(stack_array[index], min))); index++) // local_count must be a multiple of 4
  490. {
  491. }
  492. // record where it is.
  493. minIndex = 4 * index + segment + indexTable[test];
  494. }
  495. }
  496. // account for work we've already done
  497. count -= segment;
  498. // Deal with the last < STACK_ARRAY_COUNT vectors
  499. min = dotmin;
  500. index = 0;
  501. if (btUnlikely(count > 16))
  502. {
  503. for (; index + 4 <= count / 4; index += 4)
  504. { // do four dot products at a time. Carefully avoid touching the w element.
  505. float4 v0 = vertices[0];
  506. float4 v1 = vertices[1];
  507. float4 v2 = vertices[2];
  508. float4 v3 = vertices[3];
  509. vertices += 4;
  510. float4 lo0 = _mm_movelh_ps(v0, v1); // x0y0x1y1
  511. float4 hi0 = _mm_movehl_ps(v1, v0); // z0?0z1?1
  512. float4 lo1 = _mm_movelh_ps(v2, v3); // x2y2x3y3
  513. float4 hi1 = _mm_movehl_ps(v3, v2); // z2?2z3?3
  514. lo0 = lo0 * vLo;
  515. lo1 = lo1 * vLo;
  516. float4 z = _mm_shuffle_ps(hi0, hi1, 0x88);
  517. float4 x = _mm_shuffle_ps(lo0, lo1, 0x88);
  518. float4 y = _mm_shuffle_ps(lo0, lo1, 0xdd);
  519. z = z * vHi;
  520. x = x + y;
  521. x = x + z;
  522. stack_array[index] = x;
  523. min = _mm_min_ps(x, min); // control the order here so that min is never NaN even if x is nan
  524. v0 = vertices[0];
  525. v1 = vertices[1];
  526. v2 = vertices[2];
  527. v3 = vertices[3];
  528. vertices += 4;
  529. lo0 = _mm_movelh_ps(v0, v1); // x0y0x1y1
  530. hi0 = _mm_movehl_ps(v1, v0); // z0?0z1?1
  531. lo1 = _mm_movelh_ps(v2, v3); // x2y2x3y3
  532. hi1 = _mm_movehl_ps(v3, v2); // z2?2z3?3
  533. lo0 = lo0 * vLo;
  534. lo1 = lo1 * vLo;
  535. z = _mm_shuffle_ps(hi0, hi1, 0x88);
  536. x = _mm_shuffle_ps(lo0, lo1, 0x88);
  537. y = _mm_shuffle_ps(lo0, lo1, 0xdd);
  538. z = z * vHi;
  539. x = x + y;
  540. x = x + z;
  541. stack_array[index + 1] = x;
  542. min = _mm_min_ps(x, min); // control the order here so that min is never NaN even if x is nan
  543. v0 = vertices[0];
  544. v1 = vertices[1];
  545. v2 = vertices[2];
  546. v3 = vertices[3];
  547. vertices += 4;
  548. lo0 = _mm_movelh_ps(v0, v1); // x0y0x1y1
  549. hi0 = _mm_movehl_ps(v1, v0); // z0?0z1?1
  550. lo1 = _mm_movelh_ps(v2, v3); // x2y2x3y3
  551. hi1 = _mm_movehl_ps(v3, v2); // z2?2z3?3
  552. lo0 = lo0 * vLo;
  553. lo1 = lo1 * vLo;
  554. z = _mm_shuffle_ps(hi0, hi1, 0x88);
  555. x = _mm_shuffle_ps(lo0, lo1, 0x88);
  556. y = _mm_shuffle_ps(lo0, lo1, 0xdd);
  557. z = z * vHi;
  558. x = x + y;
  559. x = x + z;
  560. stack_array[index + 2] = x;
  561. min = _mm_min_ps(x, min); // control the order here so that min is never NaN even if x is nan
  562. v0 = vertices[0];
  563. v1 = vertices[1];
  564. v2 = vertices[2];
  565. v3 = vertices[3];
  566. vertices += 4;
  567. lo0 = _mm_movelh_ps(v0, v1); // x0y0x1y1
  568. hi0 = _mm_movehl_ps(v1, v0); // z0?0z1?1
  569. lo1 = _mm_movelh_ps(v2, v3); // x2y2x3y3
  570. hi1 = _mm_movehl_ps(v3, v2); // z2?2z3?3
  571. lo0 = lo0 * vLo;
  572. lo1 = lo1 * vLo;
  573. z = _mm_shuffle_ps(hi0, hi1, 0x88);
  574. x = _mm_shuffle_ps(lo0, lo1, 0x88);
  575. y = _mm_shuffle_ps(lo0, lo1, 0xdd);
  576. z = z * vHi;
  577. x = x + y;
  578. x = x + z;
  579. stack_array[index + 3] = x;
  580. min = _mm_min_ps(x, min); // control the order here so that min is never NaN even if x is nan
  581. // It is too costly to keep the index of the min here. We will look for it again later. We save a lot of work this way.
  582. }
  583. }
  584. size_t localCount = (count & -4L) - 4 * index;
  585. if (localCount)
  586. {
  587. #ifdef __APPLE__
  588. vertices += localCount; // counter the offset
  589. float4 t0, t1, t2, t3, t4;
  590. size_t byteIndex = -(localCount) * sizeof(float);
  591. float4 *sap = &stack_array[index + localCount / 4];
  592. asm volatile(
  593. ".align 4 \n\
  594. 0: movaps %[min], %[t2] // move min out of the way to avoid propagating NaNs in min \n\
  595. movaps (%[vertices], %[byteIndex], 4), %[t0] // vertices[0] \n\
  596. movaps 16(%[vertices], %[byteIndex], 4), %[t1] // vertices[1] \n\
  597. movaps %[t0], %[min] // vertices[0] \n\
  598. movlhps %[t1], %[min] // x0y0x1y1 \n\
  599. movaps 32(%[vertices], %[byteIndex], 4), %[t3] // vertices[2] \n\
  600. movaps 48(%[vertices], %[byteIndex], 4), %[t4] // vertices[3] \n\
  601. mulps %[vLo], %[min] // x0y0x1y1 * vLo \n\
  602. movhlps %[t0], %[t1] // z0w0z1w1 \n\
  603. movaps %[t3], %[t0] // vertices[2] \n\
  604. movlhps %[t4], %[t0] // x2y2x3y3 \n\
  605. movhlps %[t3], %[t4] // z2w2z3w3 \n\
  606. mulps %[vLo], %[t0] // x2y2x3y3 * vLo \n\
  607. shufps $0x88, %[t4], %[t1] // z0z1z2z3 \n\
  608. mulps %[vHi], %[t1] // z0z1z2z3 * vHi \n\
  609. movaps %[min], %[t3] // x0y0x1y1 * vLo \n\
  610. shufps $0x88, %[t0], %[min] // x0x1x2x3 * vLo.x \n\
  611. shufps $0xdd, %[t0], %[t3] // y0y1y2y3 * vLo.y \n\
  612. addps %[t3], %[min] // x + y \n\
  613. addps %[t1], %[min] // x + y + z \n\
  614. movaps %[min], (%[sap], %[byteIndex]) // record result for later scrutiny \n\
  615. minps %[t2], %[min] // record min, restore min \n\
  616. add $16, %[byteIndex] // advance loop counter\n\
  617. jnz 0b \n\
  618. "
  619. : [min] "+x"(min), [t0] "=&x"(t0), [t1] "=&x"(t1), [t2] "=&x"(t2), [t3] "=&x"(t3), [t4] "=&x"(t4), [byteIndex] "+r"(byteIndex)
  620. : [vLo] "x"(vLo), [vHi] "x"(vHi), [vertices] "r"(vertices), [sap] "r"(sap)
  621. : "memory", "cc");
  622. index += localCount / 4;
  623. #else
  624. {
  625. for (unsigned int i = 0; i < localCount / 4; i++, index++)
  626. { // do four dot products at a time. Carefully avoid touching the w element.
  627. float4 v0 = vertices[0];
  628. float4 v1 = vertices[1];
  629. float4 v2 = vertices[2];
  630. float4 v3 = vertices[3];
  631. vertices += 4;
  632. float4 lo0 = _mm_movelh_ps(v0, v1); // x0y0x1y1
  633. float4 hi0 = _mm_movehl_ps(v1, v0); // z0?0z1?1
  634. float4 lo1 = _mm_movelh_ps(v2, v3); // x2y2x3y3
  635. float4 hi1 = _mm_movehl_ps(v3, v2); // z2?2z3?3
  636. lo0 = lo0 * vLo;
  637. lo1 = lo1 * vLo;
  638. float4 z = _mm_shuffle_ps(hi0, hi1, 0x88);
  639. float4 x = _mm_shuffle_ps(lo0, lo1, 0x88);
  640. float4 y = _mm_shuffle_ps(lo0, lo1, 0xdd);
  641. z = z * vHi;
  642. x = x + y;
  643. x = x + z;
  644. stack_array[index] = x;
  645. min = _mm_min_ps(x, min); // control the order here so that max is never NaN even if x is nan
  646. }
  647. }
  648. #endif
  649. }
  650. // process the last few points
  651. if (count & 3)
  652. {
  653. float4 v0, v1, v2, x, y, z;
  654. switch (count & 3)
  655. {
  656. case 3:
  657. {
  658. v0 = vertices[0];
  659. v1 = vertices[1];
  660. v2 = vertices[2];
  661. // Calculate 3 dot products, transpose, duplicate v2
  662. float4 lo0 = _mm_movelh_ps(v0, v1); // xyxy.lo
  663. float4 hi0 = _mm_movehl_ps(v1, v0); // z?z?.lo
  664. lo0 = lo0 * vLo;
  665. z = _mm_shuffle_ps(hi0, v2, 0xa8); // z0z1z2z2
  666. z = z * vHi;
  667. float4 lo1 = _mm_movelh_ps(v2, v2); // xyxy
  668. lo1 = lo1 * vLo;
  669. x = _mm_shuffle_ps(lo0, lo1, 0x88);
  670. y = _mm_shuffle_ps(lo0, lo1, 0xdd);
  671. }
  672. break;
  673. case 2:
  674. {
  675. v0 = vertices[0];
  676. v1 = vertices[1];
  677. float4 xy = _mm_movelh_ps(v0, v1);
  678. z = _mm_movehl_ps(v1, v0);
  679. xy = xy * vLo;
  680. z = _mm_shuffle_ps(z, z, 0xa8);
  681. x = _mm_shuffle_ps(xy, xy, 0xa8);
  682. y = _mm_shuffle_ps(xy, xy, 0xfd);
  683. z = z * vHi;
  684. }
  685. break;
  686. case 1:
  687. {
  688. float4 xy = vertices[0];
  689. z = _mm_shuffle_ps(xy, xy, 0xaa);
  690. xy = xy * vLo;
  691. z = z * vHi;
  692. x = _mm_shuffle_ps(xy, xy, 0);
  693. y = _mm_shuffle_ps(xy, xy, 0x55);
  694. }
  695. break;
  696. }
  697. x = x + y;
  698. x = x + z;
  699. stack_array[index] = x;
  700. min = _mm_min_ps(x, min); // control the order here so that min is never NaN even if x is nan
  701. index++;
  702. }
  703. // if we found a new min.
  704. if (0 == segment || 0xf != _mm_movemask_ps((float4)_mm_cmpeq_ps(min, dotmin)))
  705. { // we found a new min. Search for it
  706. // find min across the min vector, place in all elements of min -- big latency hit here
  707. min = _mm_min_ps(min, (float4)_mm_shuffle_ps(min, min, 0x4e));
  708. min = _mm_min_ps(min, (float4)_mm_shuffle_ps(min, min, 0xb1));
  709. // It is slightly faster to do this part in scalar code when count < 8. However, the common case for
  710. // this where it actually makes a difference is handled in the early out at the top of the function,
  711. // so it is less than a 1% difference here. I opted for improved code size, fewer branches and reduced
  712. // complexity, and removed it.
  713. dotmin = min;
  714. // scan for the first occurence of min in the array
  715. size_t test;
  716. for (index = 0; 0 == (test = _mm_movemask_ps(_mm_cmpeq_ps(stack_array[index], min))); index++) // local_count must be a multiple of 4
  717. {
  718. }
  719. minIndex = 4 * index + segment + indexTable[test];
  720. }
  721. _mm_store_ss(dotResult, dotmin);
  722. return minIndex;
  723. }
  724. #elif defined BT_USE_NEON
  725. #define ARM_NEON_GCC_COMPATIBILITY 1
  726. #include <arm_neon.h>
  727. #include <sys/types.h>
  728. #include <sys/sysctl.h> //for sysctlbyname
  729. static long _maxdot_large_v0(const float *vv, const float *vec, unsigned long count, float *dotResult);
  730. static long _maxdot_large_v1(const float *vv, const float *vec, unsigned long count, float *dotResult);
  731. static long _maxdot_large_sel(const float *vv, const float *vec, unsigned long count, float *dotResult);
  732. static long _mindot_large_v0(const float *vv, const float *vec, unsigned long count, float *dotResult);
  733. static long _mindot_large_v1(const float *vv, const float *vec, unsigned long count, float *dotResult);
  734. static long _mindot_large_sel(const float *vv, const float *vec, unsigned long count, float *dotResult);
  735. long (*_maxdot_large)(const float *vv, const float *vec, unsigned long count, float *dotResult) = _maxdot_large_sel;
  736. long (*_mindot_large)(const float *vv, const float *vec, unsigned long count, float *dotResult) = _mindot_large_sel;
  737. static inline uint32_t btGetCpuCapabilities(void)
  738. {
  739. static uint32_t capabilities = 0;
  740. static bool testedCapabilities = false;
  741. if (0 == testedCapabilities)
  742. {
  743. uint32_t hasFeature = 0;
  744. size_t featureSize = sizeof(hasFeature);
  745. int err = sysctlbyname("hw.optional.neon_hpfp", &hasFeature, &featureSize, NULL, 0);
  746. if (0 == err && hasFeature)
  747. capabilities |= 0x2000;
  748. testedCapabilities = true;
  749. }
  750. return capabilities;
  751. }
  752. static long _maxdot_large_sel(const float *vv, const float *vec, unsigned long count, float *dotResult)
  753. {
  754. if (btGetCpuCapabilities() & 0x2000)
  755. _maxdot_large = _maxdot_large_v1;
  756. else
  757. _maxdot_large = _maxdot_large_v0;
  758. return _maxdot_large(vv, vec, count, dotResult);
  759. }
  760. static long _mindot_large_sel(const float *vv, const float *vec, unsigned long count, float *dotResult)
  761. {
  762. if (btGetCpuCapabilities() & 0x2000)
  763. _mindot_large = _mindot_large_v1;
  764. else
  765. _mindot_large = _mindot_large_v0;
  766. return _mindot_large(vv, vec, count, dotResult);
  767. }
  768. #if defined __arm__
  769. #define vld1q_f32_aligned_postincrement(_ptr) ({ float32x4_t _r; asm( "vld1.f32 {%0}, [%1, :128]!\n" : "=w" (_r), "+r" (_ptr) ); /*return*/ _r; })
  770. #else
  771. //support 64bit arm
  772. #define vld1q_f32_aligned_postincrement(_ptr) ({ float32x4_t _r = ((float32x4_t*)(_ptr))[0]; (_ptr) = (const float*) ((const char*)(_ptr) + 16L); /*return*/ _r; })
  773. #endif
  774. long _maxdot_large_v0(const float *vv, const float *vec, unsigned long count, float *dotResult)
  775. {
  776. unsigned long i = 0;
  777. float32x4_t vvec = vld1q_f32_aligned_postincrement(vec);
  778. float32x2_t vLo = vget_low_f32(vvec);
  779. float32x2_t vHi = vdup_lane_f32(vget_high_f32(vvec), 0);
  780. float32x2_t dotMaxLo = (float32x2_t){-BT_INFINITY, -BT_INFINITY};
  781. float32x2_t dotMaxHi = (float32x2_t){-BT_INFINITY, -BT_INFINITY};
  782. uint32x2_t indexLo = (uint32x2_t){0, 1};
  783. uint32x2_t indexHi = (uint32x2_t){2, 3};
  784. uint32x2_t iLo = (uint32x2_t){static_cast<uint32_t>(-1), static_cast<uint32_t>(-1)};
  785. uint32x2_t iHi = (uint32x2_t){static_cast<uint32_t>(-1), static_cast<uint32_t>(-1)};
  786. const uint32x2_t four = (uint32x2_t){4, 4};
  787. for (; i + 8 <= count; i += 8)
  788. {
  789. float32x4_t v0 = vld1q_f32_aligned_postincrement(vv);
  790. float32x4_t v1 = vld1q_f32_aligned_postincrement(vv);
  791. float32x4_t v2 = vld1q_f32_aligned_postincrement(vv);
  792. float32x4_t v3 = vld1q_f32_aligned_postincrement(vv);
  793. float32x2_t xy0 = vmul_f32(vget_low_f32(v0), vLo);
  794. float32x2_t xy1 = vmul_f32(vget_low_f32(v1), vLo);
  795. float32x2_t xy2 = vmul_f32(vget_low_f32(v2), vLo);
  796. float32x2_t xy3 = vmul_f32(vget_low_f32(v3), vLo);
  797. float32x2x2_t z0 = vtrn_f32(vget_high_f32(v0), vget_high_f32(v1));
  798. float32x2x2_t z1 = vtrn_f32(vget_high_f32(v2), vget_high_f32(v3));
  799. float32x2_t zLo = vmul_f32(z0.val[0], vHi);
  800. float32x2_t zHi = vmul_f32(z1.val[0], vHi);
  801. float32x2_t rLo = vpadd_f32(xy0, xy1);
  802. float32x2_t rHi = vpadd_f32(xy2, xy3);
  803. rLo = vadd_f32(rLo, zLo);
  804. rHi = vadd_f32(rHi, zHi);
  805. uint32x2_t maskLo = vcgt_f32(rLo, dotMaxLo);
  806. uint32x2_t maskHi = vcgt_f32(rHi, dotMaxHi);
  807. dotMaxLo = vbsl_f32(maskLo, rLo, dotMaxLo);
  808. dotMaxHi = vbsl_f32(maskHi, rHi, dotMaxHi);
  809. iLo = vbsl_u32(maskLo, indexLo, iLo);
  810. iHi = vbsl_u32(maskHi, indexHi, iHi);
  811. indexLo = vadd_u32(indexLo, four);
  812. indexHi = vadd_u32(indexHi, four);
  813. v0 = vld1q_f32_aligned_postincrement(vv);
  814. v1 = vld1q_f32_aligned_postincrement(vv);
  815. v2 = vld1q_f32_aligned_postincrement(vv);
  816. v3 = vld1q_f32_aligned_postincrement(vv);
  817. xy0 = vmul_f32(vget_low_f32(v0), vLo);
  818. xy1 = vmul_f32(vget_low_f32(v1), vLo);
  819. xy2 = vmul_f32(vget_low_f32(v2), vLo);
  820. xy3 = vmul_f32(vget_low_f32(v3), vLo);
  821. z0 = vtrn_f32(vget_high_f32(v0), vget_high_f32(v1));
  822. z1 = vtrn_f32(vget_high_f32(v2), vget_high_f32(v3));
  823. zLo = vmul_f32(z0.val[0], vHi);
  824. zHi = vmul_f32(z1.val[0], vHi);
  825. rLo = vpadd_f32(xy0, xy1);
  826. rHi = vpadd_f32(xy2, xy3);
  827. rLo = vadd_f32(rLo, zLo);
  828. rHi = vadd_f32(rHi, zHi);
  829. maskLo = vcgt_f32(rLo, dotMaxLo);
  830. maskHi = vcgt_f32(rHi, dotMaxHi);
  831. dotMaxLo = vbsl_f32(maskLo, rLo, dotMaxLo);
  832. dotMaxHi = vbsl_f32(maskHi, rHi, dotMaxHi);
  833. iLo = vbsl_u32(maskLo, indexLo, iLo);
  834. iHi = vbsl_u32(maskHi, indexHi, iHi);
  835. indexLo = vadd_u32(indexLo, four);
  836. indexHi = vadd_u32(indexHi, four);
  837. }
  838. for (; i + 4 <= count; i += 4)
  839. {
  840. float32x4_t v0 = vld1q_f32_aligned_postincrement(vv);
  841. float32x4_t v1 = vld1q_f32_aligned_postincrement(vv);
  842. float32x4_t v2 = vld1q_f32_aligned_postincrement(vv);
  843. float32x4_t v3 = vld1q_f32_aligned_postincrement(vv);
  844. float32x2_t xy0 = vmul_f32(vget_low_f32(v0), vLo);
  845. float32x2_t xy1 = vmul_f32(vget_low_f32(v1), vLo);
  846. float32x2_t xy2 = vmul_f32(vget_low_f32(v2), vLo);
  847. float32x2_t xy3 = vmul_f32(vget_low_f32(v3), vLo);
  848. float32x2x2_t z0 = vtrn_f32(vget_high_f32(v0), vget_high_f32(v1));
  849. float32x2x2_t z1 = vtrn_f32(vget_high_f32(v2), vget_high_f32(v3));
  850. float32x2_t zLo = vmul_f32(z0.val[0], vHi);
  851. float32x2_t zHi = vmul_f32(z1.val[0], vHi);
  852. float32x2_t rLo = vpadd_f32(xy0, xy1);
  853. float32x2_t rHi = vpadd_f32(xy2, xy3);
  854. rLo = vadd_f32(rLo, zLo);
  855. rHi = vadd_f32(rHi, zHi);
  856. uint32x2_t maskLo = vcgt_f32(rLo, dotMaxLo);
  857. uint32x2_t maskHi = vcgt_f32(rHi, dotMaxHi);
  858. dotMaxLo = vbsl_f32(maskLo, rLo, dotMaxLo);
  859. dotMaxHi = vbsl_f32(maskHi, rHi, dotMaxHi);
  860. iLo = vbsl_u32(maskLo, indexLo, iLo);
  861. iHi = vbsl_u32(maskHi, indexHi, iHi);
  862. indexLo = vadd_u32(indexLo, four);
  863. indexHi = vadd_u32(indexHi, four);
  864. }
  865. switch (count & 3)
  866. {
  867. case 3:
  868. {
  869. float32x4_t v0 = vld1q_f32_aligned_postincrement(vv);
  870. float32x4_t v1 = vld1q_f32_aligned_postincrement(vv);
  871. float32x4_t v2 = vld1q_f32_aligned_postincrement(vv);
  872. float32x2_t xy0 = vmul_f32(vget_low_f32(v0), vLo);
  873. float32x2_t xy1 = vmul_f32(vget_low_f32(v1), vLo);
  874. float32x2_t xy2 = vmul_f32(vget_low_f32(v2), vLo);
  875. float32x2x2_t z0 = vtrn_f32(vget_high_f32(v0), vget_high_f32(v1));
  876. float32x2_t zLo = vmul_f32(z0.val[0], vHi);
  877. float32x2_t zHi = vmul_f32(vdup_lane_f32(vget_high_f32(v2), 0), vHi);
  878. float32x2_t rLo = vpadd_f32(xy0, xy1);
  879. float32x2_t rHi = vpadd_f32(xy2, xy2);
  880. rLo = vadd_f32(rLo, zLo);
  881. rHi = vadd_f32(rHi, zHi);
  882. uint32x2_t maskLo = vcgt_f32(rLo, dotMaxLo);
  883. uint32x2_t maskHi = vcgt_f32(rHi, dotMaxHi);
  884. dotMaxLo = vbsl_f32(maskLo, rLo, dotMaxLo);
  885. dotMaxHi = vbsl_f32(maskHi, rHi, dotMaxHi);
  886. iLo = vbsl_u32(maskLo, indexLo, iLo);
  887. iHi = vbsl_u32(maskHi, indexHi, iHi);
  888. }
  889. break;
  890. case 2:
  891. {
  892. float32x4_t v0 = vld1q_f32_aligned_postincrement(vv);
  893. float32x4_t v1 = vld1q_f32_aligned_postincrement(vv);
  894. float32x2_t xy0 = vmul_f32(vget_low_f32(v0), vLo);
  895. float32x2_t xy1 = vmul_f32(vget_low_f32(v1), vLo);
  896. float32x2x2_t z0 = vtrn_f32(vget_high_f32(v0), vget_high_f32(v1));
  897. float32x2_t zLo = vmul_f32(z0.val[0], vHi);
  898. float32x2_t rLo = vpadd_f32(xy0, xy1);
  899. rLo = vadd_f32(rLo, zLo);
  900. uint32x2_t maskLo = vcgt_f32(rLo, dotMaxLo);
  901. dotMaxLo = vbsl_f32(maskLo, rLo, dotMaxLo);
  902. iLo = vbsl_u32(maskLo, indexLo, iLo);
  903. }
  904. break;
  905. case 1:
  906. {
  907. float32x4_t v0 = vld1q_f32_aligned_postincrement(vv);
  908. float32x2_t xy0 = vmul_f32(vget_low_f32(v0), vLo);
  909. float32x2_t z0 = vdup_lane_f32(vget_high_f32(v0), 0);
  910. float32x2_t zLo = vmul_f32(z0, vHi);
  911. float32x2_t rLo = vpadd_f32(xy0, xy0);
  912. rLo = vadd_f32(rLo, zLo);
  913. uint32x2_t maskLo = vcgt_f32(rLo, dotMaxLo);
  914. dotMaxLo = vbsl_f32(maskLo, rLo, dotMaxLo);
  915. iLo = vbsl_u32(maskLo, indexLo, iLo);
  916. }
  917. break;
  918. default:
  919. break;
  920. }
  921. // select best answer between hi and lo results
  922. uint32x2_t mask = vcgt_f32(dotMaxHi, dotMaxLo);
  923. dotMaxLo = vbsl_f32(mask, dotMaxHi, dotMaxLo);
  924. iLo = vbsl_u32(mask, iHi, iLo);
  925. // select best answer between even and odd results
  926. dotMaxHi = vdup_lane_f32(dotMaxLo, 1);
  927. iHi = vdup_lane_u32(iLo, 1);
  928. mask = vcgt_f32(dotMaxHi, dotMaxLo);
  929. dotMaxLo = vbsl_f32(mask, dotMaxHi, dotMaxLo);
  930. iLo = vbsl_u32(mask, iHi, iLo);
  931. *dotResult = vget_lane_f32(dotMaxLo, 0);
  932. return vget_lane_u32(iLo, 0);
  933. }
  934. long _maxdot_large_v1(const float *vv, const float *vec, unsigned long count, float *dotResult)
  935. {
  936. float32x4_t vvec = vld1q_f32_aligned_postincrement(vec);
  937. float32x4_t vLo = vcombine_f32(vget_low_f32(vvec), vget_low_f32(vvec));
  938. float32x4_t vHi = vdupq_lane_f32(vget_high_f32(vvec), 0);
  939. const uint32x4_t four = (uint32x4_t){4, 4, 4, 4};
  940. uint32x4_t local_index = (uint32x4_t){0, 1, 2, 3};
  941. uint32x4_t index = (uint32x4_t){static_cast<uint32_t>(-1), static_cast<uint32_t>(-1), static_cast<uint32_t>(-1), static_cast<uint32_t>(-1)};
  942. float32x4_t maxDot = (float32x4_t){-BT_INFINITY, -BT_INFINITY, -BT_INFINITY, -BT_INFINITY};
  943. unsigned long i = 0;
  944. for (; i + 8 <= count; i += 8)
  945. {
  946. float32x4_t v0 = vld1q_f32_aligned_postincrement(vv);
  947. float32x4_t v1 = vld1q_f32_aligned_postincrement(vv);
  948. float32x4_t v2 = vld1q_f32_aligned_postincrement(vv);
  949. float32x4_t v3 = vld1q_f32_aligned_postincrement(vv);
  950. // the next two lines should resolve to a single vswp d, d
  951. float32x4_t xy0 = vcombine_f32(vget_low_f32(v0), vget_low_f32(v1));
  952. float32x4_t xy1 = vcombine_f32(vget_low_f32(v2), vget_low_f32(v3));
  953. // the next two lines should resolve to a single vswp d, d
  954. float32x4_t z0 = vcombine_f32(vget_high_f32(v0), vget_high_f32(v1));
  955. float32x4_t z1 = vcombine_f32(vget_high_f32(v2), vget_high_f32(v3));
  956. xy0 = vmulq_f32(xy0, vLo);
  957. xy1 = vmulq_f32(xy1, vLo);
  958. float32x4x2_t zb = vuzpq_f32(z0, z1);
  959. float32x4_t z = vmulq_f32(zb.val[0], vHi);
  960. float32x4x2_t xy = vuzpq_f32(xy0, xy1);
  961. float32x4_t x = vaddq_f32(xy.val[0], xy.val[1]);
  962. x = vaddq_f32(x, z);
  963. uint32x4_t mask = vcgtq_f32(x, maxDot);
  964. maxDot = vbslq_f32(mask, x, maxDot);
  965. index = vbslq_u32(mask, local_index, index);
  966. local_index = vaddq_u32(local_index, four);
  967. v0 = vld1q_f32_aligned_postincrement(vv);
  968. v1 = vld1q_f32_aligned_postincrement(vv);
  969. v2 = vld1q_f32_aligned_postincrement(vv);
  970. v3 = vld1q_f32_aligned_postincrement(vv);
  971. // the next two lines should resolve to a single vswp d, d
  972. xy0 = vcombine_f32(vget_low_f32(v0), vget_low_f32(v1));
  973. xy1 = vcombine_f32(vget_low_f32(v2), vget_low_f32(v3));
  974. // the next two lines should resolve to a single vswp d, d
  975. z0 = vcombine_f32(vget_high_f32(v0), vget_high_f32(v1));
  976. z1 = vcombine_f32(vget_high_f32(v2), vget_high_f32(v3));
  977. xy0 = vmulq_f32(xy0, vLo);
  978. xy1 = vmulq_f32(xy1, vLo);
  979. zb = vuzpq_f32(z0, z1);
  980. z = vmulq_f32(zb.val[0], vHi);
  981. xy = vuzpq_f32(xy0, xy1);
  982. x = vaddq_f32(xy.val[0], xy.val[1]);
  983. x = vaddq_f32(x, z);
  984. mask = vcgtq_f32(x, maxDot);
  985. maxDot = vbslq_f32(mask, x, maxDot);
  986. index = vbslq_u32(mask, local_index, index);
  987. local_index = vaddq_u32(local_index, four);
  988. }
  989. for (; i + 4 <= count; i += 4)
  990. {
  991. float32x4_t v0 = vld1q_f32_aligned_postincrement(vv);
  992. float32x4_t v1 = vld1q_f32_aligned_postincrement(vv);
  993. float32x4_t v2 = vld1q_f32_aligned_postincrement(vv);
  994. float32x4_t v3 = vld1q_f32_aligned_postincrement(vv);
  995. // the next two lines should resolve to a single vswp d, d
  996. float32x4_t xy0 = vcombine_f32(vget_low_f32(v0), vget_low_f32(v1));
  997. float32x4_t xy1 = vcombine_f32(vget_low_f32(v2), vget_low_f32(v3));
  998. // the next two lines should resolve to a single vswp d, d
  999. float32x4_t z0 = vcombine_f32(vget_high_f32(v0), vget_high_f32(v1));
  1000. float32x4_t z1 = vcombine_f32(vget_high_f32(v2), vget_high_f32(v3));
  1001. xy0 = vmulq_f32(xy0, vLo);
  1002. xy1 = vmulq_f32(xy1, vLo);
  1003. float32x4x2_t zb = vuzpq_f32(z0, z1);
  1004. float32x4_t z = vmulq_f32(zb.val[0], vHi);
  1005. float32x4x2_t xy = vuzpq_f32(xy0, xy1);
  1006. float32x4_t x = vaddq_f32(xy.val[0], xy.val[1]);
  1007. x = vaddq_f32(x, z);
  1008. uint32x4_t mask = vcgtq_f32(x, maxDot);
  1009. maxDot = vbslq_f32(mask, x, maxDot);
  1010. index = vbslq_u32(mask, local_index, index);
  1011. local_index = vaddq_u32(local_index, four);
  1012. }
  1013. switch (count & 3)
  1014. {
  1015. case 3:
  1016. {
  1017. float32x4_t v0 = vld1q_f32_aligned_postincrement(vv);
  1018. float32x4_t v1 = vld1q_f32_aligned_postincrement(vv);
  1019. float32x4_t v2 = vld1q_f32_aligned_postincrement(vv);
  1020. // the next two lines should resolve to a single vswp d, d
  1021. float32x4_t xy0 = vcombine_f32(vget_low_f32(v0), vget_low_f32(v1));
  1022. float32x4_t xy1 = vcombine_f32(vget_low_f32(v2), vget_low_f32(v2));
  1023. // the next two lines should resolve to a single vswp d, d
  1024. float32x4_t z0 = vcombine_f32(vget_high_f32(v0), vget_high_f32(v1));
  1025. float32x4_t z1 = vcombine_f32(vget_high_f32(v2), vget_high_f32(v2));
  1026. xy0 = vmulq_f32(xy0, vLo);
  1027. xy1 = vmulq_f32(xy1, vLo);
  1028. float32x4x2_t zb = vuzpq_f32(z0, z1);
  1029. float32x4_t z = vmulq_f32(zb.val[0], vHi);
  1030. float32x4x2_t xy = vuzpq_f32(xy0, xy1);
  1031. float32x4_t x = vaddq_f32(xy.val[0], xy.val[1]);
  1032. x = vaddq_f32(x, z);
  1033. uint32x4_t mask = vcgtq_f32(x, maxDot);
  1034. maxDot = vbslq_f32(mask, x, maxDot);
  1035. index = vbslq_u32(mask, local_index, index);
  1036. local_index = vaddq_u32(local_index, four);
  1037. }
  1038. break;
  1039. case 2:
  1040. {
  1041. float32x4_t v0 = vld1q_f32_aligned_postincrement(vv);
  1042. float32x4_t v1 = vld1q_f32_aligned_postincrement(vv);
  1043. // the next two lines should resolve to a single vswp d, d
  1044. float32x4_t xy0 = vcombine_f32(vget_low_f32(v0), vget_low_f32(v1));
  1045. // the next two lines should resolve to a single vswp d, d
  1046. float32x4_t z0 = vcombine_f32(vget_high_f32(v0), vget_high_f32(v1));
  1047. xy0 = vmulq_f32(xy0, vLo);
  1048. float32x4x2_t zb = vuzpq_f32(z0, z0);
  1049. float32x4_t z = vmulq_f32(zb.val[0], vHi);
  1050. float32x4x2_t xy = vuzpq_f32(xy0, xy0);
  1051. float32x4_t x = vaddq_f32(xy.val[0], xy.val[1]);
  1052. x = vaddq_f32(x, z);
  1053. uint32x4_t mask = vcgtq_f32(x, maxDot);
  1054. maxDot = vbslq_f32(mask, x, maxDot);
  1055. index = vbslq_u32(mask, local_index, index);
  1056. local_index = vaddq_u32(local_index, four);
  1057. }
  1058. break;
  1059. case 1:
  1060. {
  1061. float32x4_t v0 = vld1q_f32_aligned_postincrement(vv);
  1062. // the next two lines should resolve to a single vswp d, d
  1063. float32x4_t xy0 = vcombine_f32(vget_low_f32(v0), vget_low_f32(v0));
  1064. // the next two lines should resolve to a single vswp d, d
  1065. float32x4_t z = vdupq_lane_f32(vget_high_f32(v0), 0);
  1066. xy0 = vmulq_f32(xy0, vLo);
  1067. z = vmulq_f32(z, vHi);
  1068. float32x4x2_t xy = vuzpq_f32(xy0, xy0);
  1069. float32x4_t x = vaddq_f32(xy.val[0], xy.val[1]);
  1070. x = vaddq_f32(x, z);
  1071. uint32x4_t mask = vcgtq_f32(x, maxDot);
  1072. maxDot = vbslq_f32(mask, x, maxDot);
  1073. index = vbslq_u32(mask, local_index, index);
  1074. local_index = vaddq_u32(local_index, four);
  1075. }
  1076. break;
  1077. default:
  1078. break;
  1079. }
  1080. // select best answer between hi and lo results
  1081. uint32x2_t mask = vcgt_f32(vget_high_f32(maxDot), vget_low_f32(maxDot));
  1082. float32x2_t maxDot2 = vbsl_f32(mask, vget_high_f32(maxDot), vget_low_f32(maxDot));
  1083. uint32x2_t index2 = vbsl_u32(mask, vget_high_u32(index), vget_low_u32(index));
  1084. // select best answer between even and odd results
  1085. float32x2_t maxDotO = vdup_lane_f32(maxDot2, 1);
  1086. uint32x2_t indexHi = vdup_lane_u32(index2, 1);
  1087. mask = vcgt_f32(maxDotO, maxDot2);
  1088. maxDot2 = vbsl_f32(mask, maxDotO, maxDot2);
  1089. index2 = vbsl_u32(mask, indexHi, index2);
  1090. *dotResult = vget_lane_f32(maxDot2, 0);
  1091. return vget_lane_u32(index2, 0);
  1092. }
  1093. long _mindot_large_v0(const float *vv, const float *vec, unsigned long count, float *dotResult)
  1094. {
  1095. unsigned long i = 0;
  1096. float32x4_t vvec = vld1q_f32_aligned_postincrement(vec);
  1097. float32x2_t vLo = vget_low_f32(vvec);
  1098. float32x2_t vHi = vdup_lane_f32(vget_high_f32(vvec), 0);
  1099. float32x2_t dotMinLo = (float32x2_t){BT_INFINITY, BT_INFINITY};
  1100. float32x2_t dotMinHi = (float32x2_t){BT_INFINITY, BT_INFINITY};
  1101. uint32x2_t indexLo = (uint32x2_t){0, 1};
  1102. uint32x2_t indexHi = (uint32x2_t){2, 3};
  1103. uint32x2_t iLo = (uint32x2_t){static_cast<uint32_t>(-1), static_cast<uint32_t>(-1)};
  1104. uint32x2_t iHi = (uint32x2_t){static_cast<uint32_t>(-1), static_cast<uint32_t>(-1)};
  1105. const uint32x2_t four = (uint32x2_t){4, 4};
  1106. for (; i + 8 <= count; i += 8)
  1107. {
  1108. float32x4_t v0 = vld1q_f32_aligned_postincrement(vv);
  1109. float32x4_t v1 = vld1q_f32_aligned_postincrement(vv);
  1110. float32x4_t v2 = vld1q_f32_aligned_postincrement(vv);
  1111. float32x4_t v3 = vld1q_f32_aligned_postincrement(vv);
  1112. float32x2_t xy0 = vmul_f32(vget_low_f32(v0), vLo);
  1113. float32x2_t xy1 = vmul_f32(vget_low_f32(v1), vLo);
  1114. float32x2_t xy2 = vmul_f32(vget_low_f32(v2), vLo);
  1115. float32x2_t xy3 = vmul_f32(vget_low_f32(v3), vLo);
  1116. float32x2x2_t z0 = vtrn_f32(vget_high_f32(v0), vget_high_f32(v1));
  1117. float32x2x2_t z1 = vtrn_f32(vget_high_f32(v2), vget_high_f32(v3));
  1118. float32x2_t zLo = vmul_f32(z0.val[0], vHi);
  1119. float32x2_t zHi = vmul_f32(z1.val[0], vHi);
  1120. float32x2_t rLo = vpadd_f32(xy0, xy1);
  1121. float32x2_t rHi = vpadd_f32(xy2, xy3);
  1122. rLo = vadd_f32(rLo, zLo);
  1123. rHi = vadd_f32(rHi, zHi);
  1124. uint32x2_t maskLo = vclt_f32(rLo, dotMinLo);
  1125. uint32x2_t maskHi = vclt_f32(rHi, dotMinHi);
  1126. dotMinLo = vbsl_f32(maskLo, rLo, dotMinLo);
  1127. dotMinHi = vbsl_f32(maskHi, rHi, dotMinHi);
  1128. iLo = vbsl_u32(maskLo, indexLo, iLo);
  1129. iHi = vbsl_u32(maskHi, indexHi, iHi);
  1130. indexLo = vadd_u32(indexLo, four);
  1131. indexHi = vadd_u32(indexHi, four);
  1132. v0 = vld1q_f32_aligned_postincrement(vv);
  1133. v1 = vld1q_f32_aligned_postincrement(vv);
  1134. v2 = vld1q_f32_aligned_postincrement(vv);
  1135. v3 = vld1q_f32_aligned_postincrement(vv);
  1136. xy0 = vmul_f32(vget_low_f32(v0), vLo);
  1137. xy1 = vmul_f32(vget_low_f32(v1), vLo);
  1138. xy2 = vmul_f32(vget_low_f32(v2), vLo);
  1139. xy3 = vmul_f32(vget_low_f32(v3), vLo);
  1140. z0 = vtrn_f32(vget_high_f32(v0), vget_high_f32(v1));
  1141. z1 = vtrn_f32(vget_high_f32(v2), vget_high_f32(v3));
  1142. zLo = vmul_f32(z0.val[0], vHi);
  1143. zHi = vmul_f32(z1.val[0], vHi);
  1144. rLo = vpadd_f32(xy0, xy1);
  1145. rHi = vpadd_f32(xy2, xy3);
  1146. rLo = vadd_f32(rLo, zLo);
  1147. rHi = vadd_f32(rHi, zHi);
  1148. maskLo = vclt_f32(rLo, dotMinLo);
  1149. maskHi = vclt_f32(rHi, dotMinHi);
  1150. dotMinLo = vbsl_f32(maskLo, rLo, dotMinLo);
  1151. dotMinHi = vbsl_f32(maskHi, rHi, dotMinHi);
  1152. iLo = vbsl_u32(maskLo, indexLo, iLo);
  1153. iHi = vbsl_u32(maskHi, indexHi, iHi);
  1154. indexLo = vadd_u32(indexLo, four);
  1155. indexHi = vadd_u32(indexHi, four);
  1156. }
  1157. for (; i + 4 <= count; i += 4)
  1158. {
  1159. float32x4_t v0 = vld1q_f32_aligned_postincrement(vv);
  1160. float32x4_t v1 = vld1q_f32_aligned_postincrement(vv);
  1161. float32x4_t v2 = vld1q_f32_aligned_postincrement(vv);
  1162. float32x4_t v3 = vld1q_f32_aligned_postincrement(vv);
  1163. float32x2_t xy0 = vmul_f32(vget_low_f32(v0), vLo);
  1164. float32x2_t xy1 = vmul_f32(vget_low_f32(v1), vLo);
  1165. float32x2_t xy2 = vmul_f32(vget_low_f32(v2), vLo);
  1166. float32x2_t xy3 = vmul_f32(vget_low_f32(v3), vLo);
  1167. float32x2x2_t z0 = vtrn_f32(vget_high_f32(v0), vget_high_f32(v1));
  1168. float32x2x2_t z1 = vtrn_f32(vget_high_f32(v2), vget_high_f32(v3));
  1169. float32x2_t zLo = vmul_f32(z0.val[0], vHi);
  1170. float32x2_t zHi = vmul_f32(z1.val[0], vHi);
  1171. float32x2_t rLo = vpadd_f32(xy0, xy1);
  1172. float32x2_t rHi = vpadd_f32(xy2, xy3);
  1173. rLo = vadd_f32(rLo, zLo);
  1174. rHi = vadd_f32(rHi, zHi);
  1175. uint32x2_t maskLo = vclt_f32(rLo, dotMinLo);
  1176. uint32x2_t maskHi = vclt_f32(rHi, dotMinHi);
  1177. dotMinLo = vbsl_f32(maskLo, rLo, dotMinLo);
  1178. dotMinHi = vbsl_f32(maskHi, rHi, dotMinHi);
  1179. iLo = vbsl_u32(maskLo, indexLo, iLo);
  1180. iHi = vbsl_u32(maskHi, indexHi, iHi);
  1181. indexLo = vadd_u32(indexLo, four);
  1182. indexHi = vadd_u32(indexHi, four);
  1183. }
  1184. switch (count & 3)
  1185. {
  1186. case 3:
  1187. {
  1188. float32x4_t v0 = vld1q_f32_aligned_postincrement(vv);
  1189. float32x4_t v1 = vld1q_f32_aligned_postincrement(vv);
  1190. float32x4_t v2 = vld1q_f32_aligned_postincrement(vv);
  1191. float32x2_t xy0 = vmul_f32(vget_low_f32(v0), vLo);
  1192. float32x2_t xy1 = vmul_f32(vget_low_f32(v1), vLo);
  1193. float32x2_t xy2 = vmul_f32(vget_low_f32(v2), vLo);
  1194. float32x2x2_t z0 = vtrn_f32(vget_high_f32(v0), vget_high_f32(v1));
  1195. float32x2_t zLo = vmul_f32(z0.val[0], vHi);
  1196. float32x2_t zHi = vmul_f32(vdup_lane_f32(vget_high_f32(v2), 0), vHi);
  1197. float32x2_t rLo = vpadd_f32(xy0, xy1);
  1198. float32x2_t rHi = vpadd_f32(xy2, xy2);
  1199. rLo = vadd_f32(rLo, zLo);
  1200. rHi = vadd_f32(rHi, zHi);
  1201. uint32x2_t maskLo = vclt_f32(rLo, dotMinLo);
  1202. uint32x2_t maskHi = vclt_f32(rHi, dotMinHi);
  1203. dotMinLo = vbsl_f32(maskLo, rLo, dotMinLo);
  1204. dotMinHi = vbsl_f32(maskHi, rHi, dotMinHi);
  1205. iLo = vbsl_u32(maskLo, indexLo, iLo);
  1206. iHi = vbsl_u32(maskHi, indexHi, iHi);
  1207. }
  1208. break;
  1209. case 2:
  1210. {
  1211. float32x4_t v0 = vld1q_f32_aligned_postincrement(vv);
  1212. float32x4_t v1 = vld1q_f32_aligned_postincrement(vv);
  1213. float32x2_t xy0 = vmul_f32(vget_low_f32(v0), vLo);
  1214. float32x2_t xy1 = vmul_f32(vget_low_f32(v1), vLo);
  1215. float32x2x2_t z0 = vtrn_f32(vget_high_f32(v0), vget_high_f32(v1));
  1216. float32x2_t zLo = vmul_f32(z0.val[0], vHi);
  1217. float32x2_t rLo = vpadd_f32(xy0, xy1);
  1218. rLo = vadd_f32(rLo, zLo);
  1219. uint32x2_t maskLo = vclt_f32(rLo, dotMinLo);
  1220. dotMinLo = vbsl_f32(maskLo, rLo, dotMinLo);
  1221. iLo = vbsl_u32(maskLo, indexLo, iLo);
  1222. }
  1223. break;
  1224. case 1:
  1225. {
  1226. float32x4_t v0 = vld1q_f32_aligned_postincrement(vv);
  1227. float32x2_t xy0 = vmul_f32(vget_low_f32(v0), vLo);
  1228. float32x2_t z0 = vdup_lane_f32(vget_high_f32(v0), 0);
  1229. float32x2_t zLo = vmul_f32(z0, vHi);
  1230. float32x2_t rLo = vpadd_f32(xy0, xy0);
  1231. rLo = vadd_f32(rLo, zLo);
  1232. uint32x2_t maskLo = vclt_f32(rLo, dotMinLo);
  1233. dotMinLo = vbsl_f32(maskLo, rLo, dotMinLo);
  1234. iLo = vbsl_u32(maskLo, indexLo, iLo);
  1235. }
  1236. break;
  1237. default:
  1238. break;
  1239. }
  1240. // select best answer between hi and lo results
  1241. uint32x2_t mask = vclt_f32(dotMinHi, dotMinLo);
  1242. dotMinLo = vbsl_f32(mask, dotMinHi, dotMinLo);
  1243. iLo = vbsl_u32(mask, iHi, iLo);
  1244. // select best answer between even and odd results
  1245. dotMinHi = vdup_lane_f32(dotMinLo, 1);
  1246. iHi = vdup_lane_u32(iLo, 1);
  1247. mask = vclt_f32(dotMinHi, dotMinLo);
  1248. dotMinLo = vbsl_f32(mask, dotMinHi, dotMinLo);
  1249. iLo = vbsl_u32(mask, iHi, iLo);
  1250. *dotResult = vget_lane_f32(dotMinLo, 0);
  1251. return vget_lane_u32(iLo, 0);
  1252. }
  1253. long _mindot_large_v1(const float *vv, const float *vec, unsigned long count, float *dotResult)
  1254. {
  1255. float32x4_t vvec = vld1q_f32_aligned_postincrement(vec);
  1256. float32x4_t vLo = vcombine_f32(vget_low_f32(vvec), vget_low_f32(vvec));
  1257. float32x4_t vHi = vdupq_lane_f32(vget_high_f32(vvec), 0);
  1258. const uint32x4_t four = (uint32x4_t){4, 4, 4, 4};
  1259. uint32x4_t local_index = (uint32x4_t){0, 1, 2, 3};
  1260. uint32x4_t index = (uint32x4_t){static_cast<uint32_t>(-1), static_cast<uint32_t>(-1), static_cast<uint32_t>(-1), static_cast<uint32_t>(-1)};
  1261. float32x4_t minDot = (float32x4_t){BT_INFINITY, BT_INFINITY, BT_INFINITY, BT_INFINITY};
  1262. unsigned long i = 0;
  1263. for (; i + 8 <= count; i += 8)
  1264. {
  1265. float32x4_t v0 = vld1q_f32_aligned_postincrement(vv);
  1266. float32x4_t v1 = vld1q_f32_aligned_postincrement(vv);
  1267. float32x4_t v2 = vld1q_f32_aligned_postincrement(vv);
  1268. float32x4_t v3 = vld1q_f32_aligned_postincrement(vv);
  1269. // the next two lines should resolve to a single vswp d, d
  1270. float32x4_t xy0 = vcombine_f32(vget_low_f32(v0), vget_low_f32(v1));
  1271. float32x4_t xy1 = vcombine_f32(vget_low_f32(v2), vget_low_f32(v3));
  1272. // the next two lines should resolve to a single vswp d, d
  1273. float32x4_t z0 = vcombine_f32(vget_high_f32(v0), vget_high_f32(v1));
  1274. float32x4_t z1 = vcombine_f32(vget_high_f32(v2), vget_high_f32(v3));
  1275. xy0 = vmulq_f32(xy0, vLo);
  1276. xy1 = vmulq_f32(xy1, vLo);
  1277. float32x4x2_t zb = vuzpq_f32(z0, z1);
  1278. float32x4_t z = vmulq_f32(zb.val[0], vHi);
  1279. float32x4x2_t xy = vuzpq_f32(xy0, xy1);
  1280. float32x4_t x = vaddq_f32(xy.val[0], xy.val[1]);
  1281. x = vaddq_f32(x, z);
  1282. uint32x4_t mask = vcltq_f32(x, minDot);
  1283. minDot = vbslq_f32(mask, x, minDot);
  1284. index = vbslq_u32(mask, local_index, index);
  1285. local_index = vaddq_u32(local_index, four);
  1286. v0 = vld1q_f32_aligned_postincrement(vv);
  1287. v1 = vld1q_f32_aligned_postincrement(vv);
  1288. v2 = vld1q_f32_aligned_postincrement(vv);
  1289. v3 = vld1q_f32_aligned_postincrement(vv);
  1290. // the next two lines should resolve to a single vswp d, d
  1291. xy0 = vcombine_f32(vget_low_f32(v0), vget_low_f32(v1));
  1292. xy1 = vcombine_f32(vget_low_f32(v2), vget_low_f32(v3));
  1293. // the next two lines should resolve to a single vswp d, d
  1294. z0 = vcombine_f32(vget_high_f32(v0), vget_high_f32(v1));
  1295. z1 = vcombine_f32(vget_high_f32(v2), vget_high_f32(v3));
  1296. xy0 = vmulq_f32(xy0, vLo);
  1297. xy1 = vmulq_f32(xy1, vLo);
  1298. zb = vuzpq_f32(z0, z1);
  1299. z = vmulq_f32(zb.val[0], vHi);
  1300. xy = vuzpq_f32(xy0, xy1);
  1301. x = vaddq_f32(xy.val[0], xy.val[1]);
  1302. x = vaddq_f32(x, z);
  1303. mask = vcltq_f32(x, minDot);
  1304. minDot = vbslq_f32(mask, x, minDot);
  1305. index = vbslq_u32(mask, local_index, index);
  1306. local_index = vaddq_u32(local_index, four);
  1307. }
  1308. for (; i + 4 <= count; i += 4)
  1309. {
  1310. float32x4_t v0 = vld1q_f32_aligned_postincrement(vv);
  1311. float32x4_t v1 = vld1q_f32_aligned_postincrement(vv);
  1312. float32x4_t v2 = vld1q_f32_aligned_postincrement(vv);
  1313. float32x4_t v3 = vld1q_f32_aligned_postincrement(vv);
  1314. // the next two lines should resolve to a single vswp d, d
  1315. float32x4_t xy0 = vcombine_f32(vget_low_f32(v0), vget_low_f32(v1));
  1316. float32x4_t xy1 = vcombine_f32(vget_low_f32(v2), vget_low_f32(v3));
  1317. // the next two lines should resolve to a single vswp d, d
  1318. float32x4_t z0 = vcombine_f32(vget_high_f32(v0), vget_high_f32(v1));
  1319. float32x4_t z1 = vcombine_f32(vget_high_f32(v2), vget_high_f32(v3));
  1320. xy0 = vmulq_f32(xy0, vLo);
  1321. xy1 = vmulq_f32(xy1, vLo);
  1322. float32x4x2_t zb = vuzpq_f32(z0, z1);
  1323. float32x4_t z = vmulq_f32(zb.val[0], vHi);
  1324. float32x4x2_t xy = vuzpq_f32(xy0, xy1);
  1325. float32x4_t x = vaddq_f32(xy.val[0], xy.val[1]);
  1326. x = vaddq_f32(x, z);
  1327. uint32x4_t mask = vcltq_f32(x, minDot);
  1328. minDot = vbslq_f32(mask, x, minDot);
  1329. index = vbslq_u32(mask, local_index, index);
  1330. local_index = vaddq_u32(local_index, four);
  1331. }
  1332. switch (count & 3)
  1333. {
  1334. case 3:
  1335. {
  1336. float32x4_t v0 = vld1q_f32_aligned_postincrement(vv);
  1337. float32x4_t v1 = vld1q_f32_aligned_postincrement(vv);
  1338. float32x4_t v2 = vld1q_f32_aligned_postincrement(vv);
  1339. // the next two lines should resolve to a single vswp d, d
  1340. float32x4_t xy0 = vcombine_f32(vget_low_f32(v0), vget_low_f32(v1));
  1341. float32x4_t xy1 = vcombine_f32(vget_low_f32(v2), vget_low_f32(v2));
  1342. // the next two lines should resolve to a single vswp d, d
  1343. float32x4_t z0 = vcombine_f32(vget_high_f32(v0), vget_high_f32(v1));
  1344. float32x4_t z1 = vcombine_f32(vget_high_f32(v2), vget_high_f32(v2));
  1345. xy0 = vmulq_f32(xy0, vLo);
  1346. xy1 = vmulq_f32(xy1, vLo);
  1347. float32x4x2_t zb = vuzpq_f32(z0, z1);
  1348. float32x4_t z = vmulq_f32(zb.val[0], vHi);
  1349. float32x4x2_t xy = vuzpq_f32(xy0, xy1);
  1350. float32x4_t x = vaddq_f32(xy.val[0], xy.val[1]);
  1351. x = vaddq_f32(x, z);
  1352. uint32x4_t mask = vcltq_f32(x, minDot);
  1353. minDot = vbslq_f32(mask, x, minDot);
  1354. index = vbslq_u32(mask, local_index, index);
  1355. local_index = vaddq_u32(local_index, four);
  1356. }
  1357. break;
  1358. case 2:
  1359. {
  1360. float32x4_t v0 = vld1q_f32_aligned_postincrement(vv);
  1361. float32x4_t v1 = vld1q_f32_aligned_postincrement(vv);
  1362. // the next two lines should resolve to a single vswp d, d
  1363. float32x4_t xy0 = vcombine_f32(vget_low_f32(v0), vget_low_f32(v1));
  1364. // the next two lines should resolve to a single vswp d, d
  1365. float32x4_t z0 = vcombine_f32(vget_high_f32(v0), vget_high_f32(v1));
  1366. xy0 = vmulq_f32(xy0, vLo);
  1367. float32x4x2_t zb = vuzpq_f32(z0, z0);
  1368. float32x4_t z = vmulq_f32(zb.val[0], vHi);
  1369. float32x4x2_t xy = vuzpq_f32(xy0, xy0);
  1370. float32x4_t x = vaddq_f32(xy.val[0], xy.val[1]);
  1371. x = vaddq_f32(x, z);
  1372. uint32x4_t mask = vcltq_f32(x, minDot);
  1373. minDot = vbslq_f32(mask, x, minDot);
  1374. index = vbslq_u32(mask, local_index, index);
  1375. local_index = vaddq_u32(local_index, four);
  1376. }
  1377. break;
  1378. case 1:
  1379. {
  1380. float32x4_t v0 = vld1q_f32_aligned_postincrement(vv);
  1381. // the next two lines should resolve to a single vswp d, d
  1382. float32x4_t xy0 = vcombine_f32(vget_low_f32(v0), vget_low_f32(v0));
  1383. // the next two lines should resolve to a single vswp d, d
  1384. float32x4_t z = vdupq_lane_f32(vget_high_f32(v0), 0);
  1385. xy0 = vmulq_f32(xy0, vLo);
  1386. z = vmulq_f32(z, vHi);
  1387. float32x4x2_t xy = vuzpq_f32(xy0, xy0);
  1388. float32x4_t x = vaddq_f32(xy.val[0], xy.val[1]);
  1389. x = vaddq_f32(x, z);
  1390. uint32x4_t mask = vcltq_f32(x, minDot);
  1391. minDot = vbslq_f32(mask, x, minDot);
  1392. index = vbslq_u32(mask, local_index, index);
  1393. local_index = vaddq_u32(local_index, four);
  1394. }
  1395. break;
  1396. default:
  1397. break;
  1398. }
  1399. // select best answer between hi and lo results
  1400. uint32x2_t mask = vclt_f32(vget_high_f32(minDot), vget_low_f32(minDot));
  1401. float32x2_t minDot2 = vbsl_f32(mask, vget_high_f32(minDot), vget_low_f32(minDot));
  1402. uint32x2_t index2 = vbsl_u32(mask, vget_high_u32(index), vget_low_u32(index));
  1403. // select best answer between even and odd results
  1404. float32x2_t minDotO = vdup_lane_f32(minDot2, 1);
  1405. uint32x2_t indexHi = vdup_lane_u32(index2, 1);
  1406. mask = vclt_f32(minDotO, minDot2);
  1407. minDot2 = vbsl_f32(mask, minDotO, minDot2);
  1408. index2 = vbsl_u32(mask, indexHi, index2);
  1409. *dotResult = vget_lane_f32(minDot2, 0);
  1410. return vget_lane_u32(index2, 0);
  1411. }
  1412. #else
  1413. #error Unhandled __APPLE__ arch
  1414. #endif
  1415. #endif /* __APPLE__ */