You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

_utf8validator.c 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // The MIT License (MIT)
  4. //
  5. // Copyright (c) Crossbar.io Technologies GmbH
  6. //
  7. // Permission is hereby granted, free of charge, to any person obtaining a copy
  8. // of this software and associated documentation files (the "Software"), to deal
  9. // in the Software without restriction, including without limitation the rights
  10. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. // copies of the Software, and to permit persons to whom the Software is
  12. // furnished to do so, subject to the following conditions:
  13. //
  14. // The above copyright notice and this permission notice shall be included in
  15. // all copies or substantial portions of the Software.
  16. //
  17. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. // THE SOFTWARE.
  24. //
  25. ///////////////////////////////////////////////////////////////////////////////
  26. #include <stdlib.h>
  27. #include <stdint.h>
  28. // http://stackoverflow.com/questions/11228855/header-files-for-simd-intrinsics
  29. #include <x86intrin.h>
  30. #define UTF8_ACCEPT 0
  31. #define UTF8_REJECT 1
  32. typedef struct {
  33. size_t current_index;
  34. size_t total_index;
  35. int state;
  36. int impl;
  37. } utf8_validator_t;
  38. #define UTF8_VALIDATOR_OPTIMAL 0
  39. #define UTF8_VALIDATOR_TABLE_DFA 1
  40. #define UTF8_VALIDATOR_UNROLLED_DFA 2
  41. #define UTF8_VALIDATOR_SSE2_DFA 3
  42. #define UTF8_VALIDATOR_SSE41_DFA 4
  43. int nvx_utf8vld_get_impl (void* utf8vld) {
  44. utf8_validator_t* vld = (utf8_validator_t*) utf8vld;
  45. return vld->impl;
  46. }
  47. int nvx_utf8vld_set_impl (void* utf8vld, int impl) {
  48. utf8_validator_t* vld = (utf8_validator_t*) utf8vld;
  49. if (impl) {
  50. // set requested implementation
  51. //
  52. #ifndef __SSE4_1__
  53. # ifdef __SSE2__
  54. if (impl <= UTF8_VALIDATOR_SSE2_DFA) {
  55. vld->impl = impl;
  56. }
  57. # else
  58. if (impl <= UTF8_VALIDATOR_UNROLLED_DFA) {
  59. vld->impl = impl;
  60. }
  61. # endif
  62. #else
  63. if (impl <= UTF8_VALIDATOR_SSE41_DFA) {
  64. vld->impl = impl;
  65. }
  66. #endif
  67. } else {
  68. // set optimal implementation
  69. //
  70. #ifndef __SSE4_1__
  71. # ifdef __SSE2__
  72. vld->impl = UTF8_VALIDATOR_SSE2_DFA;
  73. # else
  74. vld->impl = UTF8_VALIDATOR_UNROLLED_DFA;
  75. # endif
  76. #else
  77. vld->impl = UTF8_VALIDATOR_SSE41_DFA;
  78. #endif
  79. }
  80. return vld->impl;
  81. }
  82. void nvx_utf8vld_reset (void* utf8vld) {
  83. utf8_validator_t* vld = (utf8_validator_t*) utf8vld;
  84. vld->state = 0;
  85. vld->current_index = -1;
  86. vld->total_index = -1;
  87. }
  88. void* nvx_utf8vld_new () {
  89. void* p = malloc(sizeof(utf8_validator_t));
  90. nvx_utf8vld_reset(p);
  91. nvx_utf8vld_set_impl(p, 0);
  92. return p;
  93. }
  94. void nvx_utf8vld_free (void* utf8vld) {
  95. free (utf8vld);
  96. }
  97. // unrolled DFA from http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
  98. //
  99. static const uint8_t UTF8VALIDATOR_DFA[] __attribute__((aligned(64))) =
  100. {
  101. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
  102. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
  103. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
  104. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
  105. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
  106. 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
  107. 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
  108. 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
  109. 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
  110. 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
  111. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
  112. 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
  113. 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
  114. 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1 // s7..s8
  115. };
  116. int _nvx_utf8vld_validate_table (void* utf8vld, const uint8_t* data, size_t length) {
  117. utf8_validator_t* vld = (utf8_validator_t*) utf8vld;
  118. int state = vld->state;
  119. const uint8_t* end = data + length;
  120. while (data < end && state != 1) {
  121. state = UTF8VALIDATOR_DFA[256 + state * 16 + UTF8VALIDATOR_DFA[*data++]];
  122. }
  123. vld->state = state;
  124. if (state == 0) {
  125. // UTF8 is valid and ends on codepoint
  126. return 0;
  127. } else {
  128. if (state == 1) {
  129. // UTF8 is invalid
  130. return -1;
  131. } else {
  132. // UTF8 is valid, but does not end on codepoint (needs more data)
  133. return 1;
  134. }
  135. }
  136. }
  137. // unrolled DFA from http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
  138. //
  139. #define DFA_TRANSITION(state, octet) \
  140. if (state == 0) { \
  141. if (octet >= 0x00 && octet <= 0x7f) { \
  142. /* reflective state 0 */ \
  143. } else if (octet >= 0xc2 && octet <= 0xdf) { \
  144. state = 2; \
  145. } else if ((octet >= 0xe1 && octet <= 0xec) || octet == 0xee || octet == 0xef) { \
  146. state = 3; \
  147. } else if (octet == 0xe0) { \
  148. state = 4; \
  149. } else if (octet == 0xed) { \
  150. state = 5; \
  151. } else if (octet == 0xf4) { \
  152. state = 8; \
  153. } else if (octet == 0xf1 || octet == 0xf2 || octet == 0xf3) { \
  154. state = 7; \
  155. } else if (octet == 0xf0) { \
  156. state = 6; \
  157. } else { \
  158. state = 1; \
  159. } \
  160. } else if (state == 2) { \
  161. if (octet >= 0x80 && octet <= 0xbf) { \
  162. state = 0; \
  163. } else { \
  164. state = 1; \
  165. } \
  166. } else if (state == 3) { \
  167. if (octet >= 0x80 && octet <= 0xbf) { \
  168. state = 2; \
  169. } else { \
  170. state = 1; \
  171. } \
  172. } else if (state == 4) { \
  173. if (octet >= 0xa0 && octet <= 0xbf) { \
  174. state = 2; \
  175. } else { \
  176. state = 1; \
  177. } \
  178. } else if (state == 5) { \
  179. if (octet >= 0x80 && octet <= 0x9f) { \
  180. state = 2; \
  181. } else { \
  182. state = 1; \
  183. } \
  184. } else if (state == 6) { \
  185. if (octet >= 0x90 && octet <= 0xbf) { \
  186. state = 3; \
  187. } else { \
  188. state = 1; \
  189. } \
  190. } else if (state == 7) { \
  191. if (octet >= 0x80 && octet <= 0xbf) { \
  192. state = 3; \
  193. } else { \
  194. state = 1; \
  195. } \
  196. } else if (state == 8) { \
  197. if (octet >= 0x80 && octet <= 0x8f) { \
  198. state = 3; \
  199. } else { \
  200. state = 1; \
  201. } \
  202. } else if (state == 1) { \
  203. /* refective state 1 */ \
  204. } else { \
  205. /* should not arrive here */ \
  206. }
  207. int _nvx_utf8vld_validate_unrolled (void* utf8vld, const uint8_t* data, size_t length) {
  208. utf8_validator_t* vld = (utf8_validator_t*) utf8vld;
  209. int state = vld->state;
  210. const uint8_t* tail_end = data + length;
  211. while (data < tail_end && state != 1) {
  212. // get tail octet
  213. int octet = *data;
  214. // do the DFA
  215. DFA_TRANSITION(state, octet);
  216. ++data;
  217. }
  218. vld->state = state;
  219. if (state == 0) {
  220. // UTF8 is valid and ends on codepoint
  221. return 0;
  222. } else {
  223. if (state == 1) {
  224. // UTF8 is invalid
  225. return -1;
  226. } else {
  227. // UTF8 is valid, but does not end on codepoint (needs more data)
  228. return 1;
  229. }
  230. }
  231. }
  232. /*
  233. __m128i _mm_load_si128 (__m128i const* mem_addr)
  234. #include "emmintrin.h"
  235. Instruction: movdqa
  236. CPUID Feature Flag: SSE2
  237. int _mm_movemask_epi8 (__m128i a)
  238. #include "emmintrin.h"
  239. Instruction: pmovmskb
  240. CPUID Feature Flag: SSE2
  241. __m128i _mm_srli_si128 (__m128i a, int imm)
  242. #include "emmintrin.h"
  243. Instruction: psrldq
  244. CPUID Feature Flag: SSE2
  245. int _mm_cvtsi128_si32 (__m128i a)
  246. #include "emmintrin.h"
  247. Instruction: movd
  248. CPUID Feature Flag: SSE2
  249. int _mm_extract_epi16 (__m128i a, int imm)
  250. #include "emmintrin.h"
  251. Instruction: pextrw
  252. CPUID Feature Flag: SSE2
  253. int _mm_extract_epi8 (__m128i a, const int imm)
  254. #include "smmintrin.h"
  255. Instruction: pextrb
  256. CPUID Feature Flag: SSE4.1
  257. */
  258. #ifdef __SSE2__
  259. int _nvx_utf8vld_validate_sse2 (void* utf8vld, const uint8_t* data, size_t length) {
  260. utf8_validator_t* vld = (utf8_validator_t*) utf8vld;
  261. int state = vld->state;
  262. const uint8_t* tail_end = data + length;
  263. // process unaligned head (sub 16 octets)
  264. //
  265. size_t head_len = ((size_t) data) % sizeof(__m128i);
  266. if (head_len) {
  267. const uint8_t* head_end = data + head_len;
  268. while (data < head_end && state != UTF8_REJECT) {
  269. // get head octet
  270. int octet = *data;
  271. // do the DFA
  272. DFA_TRANSITION(state, octet);
  273. ++data;
  274. }
  275. }
  276. // process aligned middle (16 octet chunks)
  277. //
  278. const __m128i* ptr = ((const __m128i*) data);
  279. const __m128i* end = ((const __m128i*) data) + ((length - head_len) / sizeof(__m128i));
  280. while (ptr < end && state != UTF8_REJECT) {
  281. __builtin_prefetch(ptr + 1, 0, 3);
  282. //__builtin_prefetch(ptr + 4, 0, 3); // 16*4=64: cache-line prefetch
  283. __m128i xmm1 = _mm_load_si128(ptr);
  284. if (__builtin_expect(state || _mm_movemask_epi8(xmm1), 0)) {
  285. // copy to different reg - this allows the prefetching to
  286. // do its job in the meantime (I guess ..)
  287. // SSE2 variant
  288. //
  289. int octet;
  290. // octet 0
  291. octet = 0xff & _mm_cvtsi128_si32(xmm1);
  292. DFA_TRANSITION(state, octet);
  293. // octet 1
  294. xmm1 = _mm_srli_si128(xmm1, 1);
  295. octet = 0xff & _mm_cvtsi128_si32(xmm1);
  296. DFA_TRANSITION(state, octet);
  297. // octet 2
  298. xmm1 = _mm_srli_si128(xmm1, 1);
  299. octet = 0xff & _mm_cvtsi128_si32(xmm1);
  300. DFA_TRANSITION(state, octet);
  301. // octet 3
  302. xmm1 = _mm_srli_si128(xmm1, 1);
  303. octet = 0xff & _mm_cvtsi128_si32(xmm1);
  304. DFA_TRANSITION(state, octet);
  305. // octet 4
  306. xmm1 = _mm_srli_si128(xmm1, 1);
  307. octet = 0xff & _mm_cvtsi128_si32(xmm1);
  308. DFA_TRANSITION(state, octet);
  309. // octet 5
  310. xmm1 = _mm_srli_si128(xmm1, 1);
  311. octet = 0xff & _mm_cvtsi128_si32(xmm1);
  312. DFA_TRANSITION(state, octet);
  313. // octet 6
  314. xmm1 = _mm_srli_si128(xmm1, 1);
  315. octet = 0xff & _mm_cvtsi128_si32(xmm1);
  316. DFA_TRANSITION(state, octet);
  317. // octet 7
  318. xmm1 = _mm_srli_si128(xmm1, 1);
  319. octet = 0xff & _mm_cvtsi128_si32(xmm1);
  320. DFA_TRANSITION(state, octet);
  321. // octet 8
  322. xmm1 = _mm_srli_si128(xmm1, 1);
  323. octet = 0xff & _mm_cvtsi128_si32(xmm1);
  324. DFA_TRANSITION(state, octet);
  325. // octet 9
  326. xmm1 = _mm_srli_si128(xmm1, 1);
  327. octet = 0xff & _mm_cvtsi128_si32(xmm1);
  328. DFA_TRANSITION(state, octet);
  329. // octet 10
  330. xmm1 = _mm_srli_si128(xmm1, 1);
  331. octet = 0xff & _mm_cvtsi128_si32(xmm1);
  332. DFA_TRANSITION(state, octet);
  333. // octet 11
  334. xmm1 = _mm_srli_si128(xmm1, 1);
  335. octet = 0xff & _mm_cvtsi128_si32(xmm1);
  336. DFA_TRANSITION(state, octet);
  337. // octet 12
  338. xmm1 = _mm_srli_si128(xmm1, 1);
  339. octet = 0xff & _mm_cvtsi128_si32(xmm1);
  340. DFA_TRANSITION(state, octet);
  341. // octet 13
  342. xmm1 = _mm_srli_si128(xmm1, 1);
  343. octet = 0xff & _mm_cvtsi128_si32(xmm1);
  344. DFA_TRANSITION(state, octet);
  345. // octet 14
  346. xmm1 = _mm_srli_si128(xmm1, 1);
  347. octet = 0xff & _mm_cvtsi128_si32(xmm1);
  348. DFA_TRANSITION(state, octet);
  349. // octet 15
  350. xmm1 = _mm_srli_si128(xmm1, 1);
  351. octet = 0xff & _mm_cvtsi128_si32(xmm1);
  352. DFA_TRANSITION(state, octet);
  353. }
  354. ++ptr;
  355. }
  356. // process unaligned tail (sub 16 octets)
  357. //
  358. const uint8_t* tail_ptr = (const uint8_t*) ptr;
  359. while (tail_ptr < tail_end && state != UTF8_REJECT) {
  360. // get tail octet
  361. int octet = *tail_ptr;
  362. // do the DFA
  363. DFA_TRANSITION(state, octet);
  364. ++tail_ptr;
  365. }
  366. vld->state = state;
  367. if (state == UTF8_ACCEPT) {
  368. // UTF8 is valid and ends on codepoint
  369. return 0;
  370. } else {
  371. if (state == UTF8_REJECT) {
  372. // UTF8 is invalid
  373. return -1;
  374. } else {
  375. // UTF8 is valid, but does not end on codepoint (needs more data)
  376. return 1;
  377. }
  378. }
  379. }
  380. #endif
  381. #ifdef __SSE4_1__
  382. int _nvx_utf8vld_validate_sse4 (void* utf8vld, const uint8_t* data, size_t length) {
  383. utf8_validator_t* vld = (utf8_validator_t*) utf8vld;
  384. int state = vld->state;
  385. const uint8_t* tail_end = data + length;
  386. // process unaligned head (sub 16 octets)
  387. //
  388. size_t head_len = ((size_t) data) % sizeof(__m128i);
  389. if (head_len) {
  390. const uint8_t* head_end = data + head_len;
  391. while (data < head_end && state != UTF8_REJECT) {
  392. // get head octet
  393. int octet = *data;
  394. // do the DFA
  395. DFA_TRANSITION(state, octet);
  396. ++data;
  397. }
  398. }
  399. // process aligned middle (16 octet chunks)
  400. //
  401. const __m128i* ptr = ((const __m128i*) data);
  402. const __m128i* end = ((const __m128i*) data) + ((length - head_len) / sizeof(__m128i));
  403. while (ptr < end && state != UTF8_REJECT) {
  404. __builtin_prefetch(ptr + 1, 0, 3);
  405. //__builtin_prefetch(ptr + 4, 0, 3); // 16*4=64: cache-line prefetch
  406. __m128i xmm1 = _mm_load_si128(ptr);
  407. if (__builtin_expect(state || _mm_movemask_epi8(xmm1), 0)) {
  408. // copy to different reg - this allows the prefetching to
  409. // do its job in the meantime (I guess ..)
  410. // SSE4.1 variant
  411. //
  412. int octet;
  413. // octet 0
  414. octet = _mm_extract_epi8(xmm1, 0);
  415. DFA_TRANSITION(state, octet);
  416. // octet 1
  417. octet = _mm_extract_epi8(xmm1, 1);
  418. DFA_TRANSITION(state, octet);
  419. // octet 2
  420. octet = _mm_extract_epi8(xmm1, 2);
  421. DFA_TRANSITION(state, octet);
  422. // octet 3
  423. octet = _mm_extract_epi8(xmm1, 3);
  424. DFA_TRANSITION(state, octet);
  425. // octet 4
  426. octet = _mm_extract_epi8(xmm1, 4);
  427. DFA_TRANSITION(state, octet);
  428. // octet 5
  429. octet = _mm_extract_epi8(xmm1, 5);
  430. DFA_TRANSITION(state, octet);
  431. // octet 6
  432. octet = _mm_extract_epi8(xmm1, 6);
  433. DFA_TRANSITION(state, octet);
  434. // octet 7
  435. octet = _mm_extract_epi8(xmm1, 7);
  436. DFA_TRANSITION(state, octet);
  437. // octet 8
  438. octet = _mm_extract_epi8(xmm1, 8);
  439. DFA_TRANSITION(state, octet);
  440. // octet 9
  441. octet = _mm_extract_epi8(xmm1, 9);
  442. DFA_TRANSITION(state, octet);
  443. // octet 10
  444. octet = _mm_extract_epi8(xmm1, 10);
  445. DFA_TRANSITION(state, octet);
  446. // octet 11
  447. octet = _mm_extract_epi8(xmm1, 11);
  448. DFA_TRANSITION(state, octet);
  449. // octet 12
  450. octet = _mm_extract_epi8(xmm1, 12);
  451. DFA_TRANSITION(state, octet);
  452. // octet 13
  453. octet = _mm_extract_epi8(xmm1, 13);
  454. DFA_TRANSITION(state, octet);
  455. // octet 14
  456. octet = _mm_extract_epi8(xmm1, 14);
  457. DFA_TRANSITION(state, octet);
  458. // octet 15
  459. octet = _mm_extract_epi8(xmm1, 15);
  460. DFA_TRANSITION(state, octet);
  461. }
  462. ++ptr;
  463. }
  464. // process unaligned tail (sub 16 octets)
  465. //
  466. const uint8_t* tail_ptr = (const uint8_t*) ptr;
  467. while (tail_ptr < tail_end && state != UTF8_REJECT) {
  468. // get tail octet
  469. int octet = *tail_ptr;
  470. // do the DFA
  471. DFA_TRANSITION(state, octet);
  472. ++tail_ptr;
  473. }
  474. vld->state = state;
  475. if (state == UTF8_ACCEPT) {
  476. // UTF8 is valid and ends on codepoint
  477. return 0;
  478. } else {
  479. if (state == UTF8_REJECT) {
  480. // UTF8 is invalid
  481. return -1;
  482. } else {
  483. // UTF8 is valid, but does not end on codepoint (needs more data)
  484. return 1;
  485. }
  486. }
  487. }
  488. #endif
  489. int nvx_utf8vld_validate (void* utf8vld, const uint8_t* data, size_t length) {
  490. utf8_validator_t* vld = (utf8_validator_t*) utf8vld;
  491. switch (vld->impl) {
  492. case UTF8_VALIDATOR_TABLE_DFA:
  493. return _nvx_utf8vld_validate_table(utf8vld, data, length);
  494. case UTF8_VALIDATOR_UNROLLED_DFA:
  495. return _nvx_utf8vld_validate_unrolled(utf8vld, data, length);
  496. #ifdef __SSE2__
  497. case UTF8_VALIDATOR_SSE2_DFA:
  498. return _nvx_utf8vld_validate_table(utf8vld, data, length);
  499. #endif
  500. #ifdef __SSE4_1__
  501. case UTF8_VALIDATOR_SSE41_DFA:
  502. return _nvx_utf8vld_validate_table(utf8vld, data, length);
  503. #endif
  504. default:
  505. return _nvx_utf8vld_validate_table(utf8vld, data, length);
  506. }
  507. }