btVector3.cpp 68 KB

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