{"id":486287,"date":"2026-07-06T07:38:17","date_gmt":"2026-07-06T07:38:17","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=486287"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=486287","title":{"rendered":"Stream compaction \u043d\u0430 NEON. \u0412\u0435\u043a\u0442\u043e\u0440\u0438\u0437\u0443\u0435\u043c copy_if"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h3>\u0417\u0430\u0434\u0430\u0447\u0430<\/h3>\n<p>\u0414\u0430\u043d\u044b \u043c\u0430\u0441\u0441\u0438\u0432\u044b <code>a<\/code> \u0438 <code>out<\/code>. \u041d\u0443\u0436\u043d\u043e \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0432 <code>out<\/code> \u043f\u043e\u0434\u0440\u044f\u0434, \u0431\u0435\u0437 \u043f\u0440\u043e\u0431\u0435\u043b\u043e\u0432, \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b <code>a<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u044e\u0442 \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u0443\u0441\u043b\u043e\u0432\u0438\u044e. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u2014 \u0443\u0441\u043b\u043e\u0432\u0438\u0435 <code>a[i] &gt; threshold, a[i] \u2208 (0, 1), threshold \u2208 {0, 0.5, 1}.<\/code><\/p>\n<h3>\u041f\u043e\u0447\u0435\u043c\u0443 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u0441\u0434\u0430\u0435\u0442\u0441\u044f<\/h3>\n<p>\u041e\u0434\u0438\u043d <code>if<\/code> \u0432\u043d\u0443\u0442\u0440\u0438 \u0446\u0438\u043a\u043b\u0430 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u043e\u043d\u044f\u0435\u0442 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0441 112 \u0434\u043e 2.6 GB\/s. \u041a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0432\u0435\u043a\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u2014 \u0432 NEON \u043d\u0435\u0442 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0435\u0439 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438. \u0421\u0442\u0430\u0442\u044c\u044f \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0435\u0435.<\/p>\n<pre><code class=\"cpp\">auto copy_if(const float* a, float* out, size_t n) {    size_t j = 0;    for (size_t i = 0; i &lt; n; ++i) {        if (a[i] &gt; 0) out[j++] = a[i];    }    return j;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412 \u0437\u0430\u0434\u0430\u0447\u0435 copy_if \u0432\u044b\u0445\u043e\u0434\u043d\u043e\u0439 \u043a\u0443\u0440\u0441\u043e\u0440 (\u0432 \u043a\u043e\u0434\u0435 &#8212; <code>j<\/code>) \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u043e\u044d\u0442\u043e\u043c\u0443, \u0447\u0442\u043e\u0431\u044b \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u0432\u0435\u043a\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043b, \u043d\u0443\u0436\u043d\u0430 compress-\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f (\u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430 \u043f\u043e\u0434\u0440\u044f\u0434 \u0432 \u0435\u0433\u043e \u043d\u0430\u0447\u0430\u043b\u043e, \u0431\u0435\u0437 \u0434\u044b\u0440\u043e\u043a), \u0430 \u0432 NEON \u0435\u0435 \u043d\u0435\u0442, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u0441\u0434\u0430\u0435\u0442\u0441\u044f:<\/p>\n<pre><code>clang++ -O3 -Rpass-analysis=loop-vectorize -std=c++23 main.cpp -o mainmain.cpp:5:5: remark: loop not vectorized: value that could not be identified as reduction is used outside the loop [-Rpass-analysis=loop-vectorize]5 | for (size_t i = 0; i &lt; n; ++i) {| ^main.cpp:6:23: remark: loop not vectorized: cannot identify array bounds [-Rpass-analysis=loop-vectorize]6 | if (a[i] &gt; 0) out[j++] = a[i];<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412\u0435\u043a\u0442\u043e\u0440\u0438\u0437\u0430\u0442\u043e\u0440 clang \u0443\u043c\u0435\u0435\u0442 \u043a\u043b\u0430\u0441\u0441\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c <code>j<\/code> \u043b\u0438\u0431\u043e \u043a\u0430\u043a induction (\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0448\u0430\u0433), \u043b\u0438\u0431\u043e \u043a\u0430\u043a reduction (\u0441\u0432\u0435\u0440\u0442\u043a\u0430). <code>j<\/code> \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0438 \u0442\u0435\u043c, \u043d\u0438 \u0434\u0440\u0443\u0433\u0438\u043c \u2014 \u043e\u043d \u043a\u0443\u0440\u0441\u043e\u0440, \u0437\u0430\u0432\u0438\u0441\u044f\u0449\u0438\u0439 \u043e\u0442 \u0434\u0430\u043d\u043d\u044b\u0445. \u041a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u043d\u0435 \u0443\u043c\u0435\u0435\u0442 \u0432\u0435\u043a\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u0432\u0438\u0434 \u043a\u0443\u0440\u0441\u043e\u0440\u043e\u0432. \u0412\u0442\u043e\u0440\u0430\u044f \u0440\u0435\u043c\u0430\u0440\u043a\u0430 \u043e\u0442\u0441\u044e\u0434\u0430 \u0436\u0435: \u043e\u043d \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u044c \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0439 \u043a <code>out<\/code>.<\/p>\n<h3>\u0417\u0430\u043c\u0435\u0440: \u0434\u0432\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0441\u043a\u0430\u043b\u044f\u0440\u0430<\/h3>\n<p><em>\u0432\u0441\u0435 \u0437\u0430\u043c\u0435\u0440\u044b: Apple M5; clang++ -O3 -std=c++23 -march=native; GB\/s = (2n * 4 \u0431\u0430\u0439\u0442\u0430) \/ \u0432\u0440\u0435\u043c\u044f, \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0438\u0437 3e9 \/ n \u043f\u0440\u043e\u0433\u043e\u043d\u043e\u0432; cache: n=1e5, DRAM: n=1e7<\/em><\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u0424\u0443\u043d\u043a\u0446\u0438\u044f<\/p>\n<\/th>\n<th>\n<p align=\"left\">ms (cache)<\/p>\n<\/th>\n<th>\n<p align=\"left\">GB\/s (cache)<\/p>\n<\/th>\n<th>\n<p align=\"left\">ms (DRAM)<\/p>\n<\/th>\n<th>\n<p align=\"left\">GB\/s (DRAM)<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">copy a[i]<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.004<\/p>\n<\/td>\n<td>\n<p align=\"left\">195<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.71<\/p>\n<\/td>\n<td>\n<p align=\"left\">112<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">copy a[i] if a[i] &gt; 0<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.022<\/p>\n<\/td>\n<td>\n<p align=\"left\">37<\/p>\n<\/td>\n<td>\n<p align=\"left\">2.41<\/p>\n<\/td>\n<td>\n<p align=\"left\">33<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">copy a[i] if a[i] &gt; 0.5<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.258<\/p>\n<\/td>\n<td>\n<p align=\"left\">3.1<\/p>\n<\/td>\n<td>\n<p align=\"left\">30.61<\/p>\n<\/td>\n<td>\n<p align=\"left\">2.6<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">copy a[i] if a[i] &gt; 1<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.021<\/p>\n<\/td>\n<td>\n<p align=\"left\">37<\/p>\n<\/td>\n<td>\n<p align=\"left\">2.39<\/p>\n<\/td>\n<td>\n<p align=\"left\">33<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u201ccopy a[i]\u201d \u2014 \u0442\u043e\u0442 \u0436\u0435 \u0446\u0438\u043a\u043b, \u043d\u043e \u0431\u0435\u0437 \u0443\u0441\u043b\u043e\u0432\u0438\u044f, \u0435\u0433\u043e \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u0432\u0435\u043a\u0442\u043e\u0440\u0438\u0437\u0443\u0435\u0442. \u0412\u0441\u044f \u0440\u0430\u0437\u043d\u0438\u0446\u0430 \u0441 \u043d\u0438\u043c \u0432 \u043e\u0434\u043d\u043e\u043c if. \u0414\u0430\u043d\u043d\u044b\u0435 \u0442\u0435 \u0436\u0435, \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u043e\u0441\u0442\u044c \u0432\u0435\u0442\u043a\u0438:<\/p>\n<ol>\n<li>\n<p>&gt; 0 (\u0432\u0441\u0435\u0433\u0434\u0430 true) \u0438 &gt; 1 (\u0432\u0441\u0435\u0433\u0434\u0430 false): branch predictor \u043d\u0435 \u043f\u0440\u043e\u043c\u0430\u0445\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u2192 33 GB\/s. \u0418\u0437-\u0437\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u044f \u0432\u0435\u043a\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043f\u0430\u0434\u0430\u0435\u0442 \u0432 3 \u0440\u0430\u0437\u0430<\/p>\n<\/li>\n<li>\n<p>&gt; 0.5 (50\/50): \u043f\u0440\u043e\u043c\u0430\u0445 \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0432\u0442\u043e\u0440\u043e\u043c \u2192 3 GB\/s<\/p>\n<\/li>\n<\/ol>\n<p>\u0422\u0440\u044e\u043a \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442 \u043e\u0431\u0435 \u044d\u0442\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b.<\/p>\n<h3>\u0422\u0440\u044e\u043a 1: \u044d\u043c\u0443\u043b\u0438\u0440\u0443\u0435\u043c compress<\/h3>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u0441\u0447\u0438\u0442\u0430\u0435\u043c <code>n<\/code> \u043a\u0440\u0430\u0442\u043d\u044b\u043c \u0448\u0438\u0440\u0438\u043d\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430; \u0445\u0432\u043e\u0441\u0442 \u2014 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u0442\u0435\u043c\u0430, \u043a \u0442\u0440\u044e\u043a\u0443 \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u044f \u043d\u0435 \u0438\u043c\u0435\u0435\u0442. \u0415\u0449\u0435:<\/p>\n<ol>\n<li>\n<p>\u0420\u0430\u0437\u043c\u0435\u0440 <code>out<\/code> \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c &gt;= n.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0443\u0441\u0442\u044c \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0432\u044b\u0431\u0440\u0430\u043b <code>cnt<\/code> \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u0442\u043e\u0433\u0434\u0430 \u0432\u0441\u0435 \u0432 <code>out[cnt, n)<\/code> \u0431\u0443\u0434\u0435\u0442 \u043d\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043e (\u043c\u0443\u0441\u043e\u0440). \u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c, \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0449\u0438\u0439 \u0447\u0438\u0441\u0442\u043e\u0442\u0443 \u0445\u0432\u043e\u0441\u0442\u0430, \u043d\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043a \u0438\u0434\u0435\u0435 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u043e\u0432\u043e\u0433\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u0442\u0441\u044f.<\/p>\n<\/li>\n<\/ol>\n<p>\u0412 NEON \u043d\u0435\u0442 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0441\u0436\u0430\u0442\u0438\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u044d\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0435.<\/p>\n<p>(\u0421\u0442\u043e\u0438\u0442 \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u0441\u0430\u043c \u043f\u0440\u0438\u0451\u043c \u2014 \u043d\u0435 \u043d\u043e\u0432\u044b\u0439. \u041b\u0435\u043c\u0438\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0435\u0433\u043e \u0435\u0449\u0435 \u0432 2017 \u0433\u043e\u0434\u0443 \u043d\u0430 SSE <a href=\"https:\/\/lemire.me\/blog\/2017\/01\/20\/how-quickly-can-you-remove-spaces-from-a-string\/\" rel=\"noopener noreferrer nofollow\">link<\/a>. \u041d\u043e \u043d\u0430 NEON \u043d\u0435\u0442 \u043d\u0438 movemask, \u043d\u0438 \u0434\u0435\u0448\u0435\u0432\u043e\u0433\u043e popcnt &#8212; \u0434\u0430\u043b\u044c\u0448\u0435 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0435 \u044d\u0442\u043e \u0438\u0437 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0435\u0441\u0442\u044c)<\/p>\n<p>\u0427\u0442\u043e \u0434\u043e\u043b\u0436\u0435\u043d \u0443\u043c\u0435\u0442\u044c \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0430\u0448 \u0430\u043d\u0430\u043b\u043e\u0433 compress:<\/p>\n<ol>\n<li>\n<p>\u041f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0440\u0435\u0433\u0438\u0441\u0442\u0440 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 <code>a<\/code> \u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440-\u043c\u0430\u0441\u043a\u0443, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0431\u043e\u0440.<\/p>\n<\/li>\n<li>\n<p>\u0421\u043a\u0430\u0437\u0430\u0442\u044c, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0438\u0437 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430 \u043c\u044b \u0432\u0437\u044f\u043b\u0438 (\u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c <code>out<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0432 <code>out<\/code>.<\/p>\n<\/li>\n<\/ol>\n<h4>tbl: \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u0430\u044f \u0432\u044b\u0431\u043e\u0440\u043a\u0430 \u0431\u0430\u0439\u0442<\/h4>\n<p>\u0412 NEON \u0435\u0441\u0442\u044c \u0441\u0435\u043c\u0435\u0439\u0441\u0442\u0432\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0439 table-lookup (tbl), \u0438\u0445 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u2014 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u0430\u044f \u0432\u044b\u0431\u043e\u0440\u043a\u0430\/\u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0431\u0430\u0439\u0442. \u0418\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0434\u0432\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430:<\/p>\n<ol>\n<li>\n<p>\u0422\u0430\u0431\u043b\u0438\u0446\u0430 (table) \u2014 \u0431\u0430\u0439\u0442\u044b, \u043e\u0442\u043a\u0443\u0434\u0430 \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c.<\/p>\n<\/li>\n<li>\n<p>\u0418\u043d\u0434\u0435\u043a\u0441\u044b (index) \u2014 \u043d\u043e\u043c\u0435\u0440\u0430 \u0431\u0430\u0439\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0443\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c.<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u0440\u043e\u0449\u0435 \u0433\u043e\u0432\u043e\u0440\u044f \u2014 \u044d\u0442\u043e SIMD-\u0430\u043d\u0430\u043b\u043e\u0433 out[i] = table[index[i]].<\/p>\n<p>\u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044e vqtbl1q_u8:<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u0447\u0430\u0441\u0442\u044c<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">v<\/p>\n<\/td>\n<td>\n<p align=\"left\">vector intrinsic<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">q<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0442\u0430\u0431\u043b\u0438\u0446\u0430 &#8212; \u0438\u0437 128-\u0431\u0438\u0442\u043d\u044b\u0445 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u043e\u0432<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">tbl<\/p>\n<\/td>\n<td>\n<p align=\"left\">table lookup<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">1<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u043e\u0432 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">q<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0438 \u0438\u043d\u0434\u0435\u043a\u0441\u044b &#8212; 128-\u0431\u0438\u0442\u043d\u044b\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u044b<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">u8<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0442\u0430\u0431\u043b\u0438\u0446\u044b &#8212; uint8_t<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p><code>tbl<\/code> \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0431\u0430\u0439\u0442\u044b, \u0430 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u0442\u044c float (4 \u0431\u0430\u0439\u0442\u0430). \u0417\u043d\u0430\u0447\u0438\u0442, index \u0431\u0443\u0434\u0435\u043c \u0434\u0435\u043b\u0430\u0442\u044c \u0431\u043b\u043e\u043a\u0430\u043c\u0438 \u043f\u043e 4 \u0431\u0430\u0439\u0442\u0430: \u0447\u0442\u043e\u0431\u044b \u0432\u0437\u044f\u0442\u044c \u0432\u0442\u043e\u0440\u043e\u0439 (0-based) float \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430, \u0432 index \u043f\u043e\u0439\u0434\u0443\u0442 \u0435\u0433\u043e \u0431\u0430\u0439\u0442\u044b [8, 9, 10, 11] (\u0432\u0442\u043e\u0440\u043e\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441\u043e \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u044f 2 *sizeof(float) = 8).<\/p>\n<p>\u0421\u0447\u0438\u0442\u0430\u0442\u044c index \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u0434\u043e\u043b\u0433\u043e. \u0412\u0441\u0435\u0433\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 16 (4 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0432\u0437\u044f\u0442\u044c\/\u0432\u044b\u043a\u0438\u043d\u0443\u0442\u044c), \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u0441\u0447\u0438\u0442\u0430\u0435\u043c \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0432\u0441\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b index. \u041d\u043e \u0447\u0442\u043e\u0431\u044b \u043f\u043e \u043c\u0430\u0441\u043a\u0435 \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c index, \u043d\u0430\u0434\u043e \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u043c\u0430\u0441\u043a\u0443 \u0432 \u0447\u0438\u0441\u043b\u043e (\u043d\u0430\u0437\u043e\u0432\u0435\u043c \u0435\u0433\u043e idx):<\/p>\n<h4>\u041c\u0430\u0441\u043a\u0430 \u2192 idx<\/h4>\n<p>\u041c\u0430\u0441\u043a\u0430 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 4 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u043a\u0430\u0436\u0434\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u2014 \u043b\u0438\u0431\u043e 0x00000000 (false), \u043b\u0438\u0431\u043e 0xFFFFFFFF (true). \u0425\u043e\u0442\u0438\u043c: \u0435\u0441\u043b\u0438 i-\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 true \u2014 \u0432\u044b\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432 idx i-\u0439 \u0431\u0438\u0442. \u0422\u0440\u044e\u043a: mask &amp; [1, 2, 4, 8]. \u0422\u0430\u043a \u043a\u0430\u043a 0xFFFFFFFF &amp; x = x, \u0432 \u0438\u0441\u0442\u0438\u043d\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0445 \u043e\u0441\u0442\u0430\u043d\u0435\u0442\u0441\u044f \u0432\u0435\u0441 (1\/2\/4\/8), \u0430 \u0432 \u043b\u043e\u0436\u043d\u044b\u0445 0. \u0421\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u043c \u0432\u0441\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u0431\u043e\u0439 \u2014 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0447\u0438\u0441\u043b\u043e 0\u202615.<\/p>\n<pre><code class=\"cpp\">std::array&lt;uint32_t, 4&gt; weights{1, 2, 4, 8};size_t idx = vaddvq_u32(vandq_u32(mask, vld1q_u32(weights.data())));<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p>vld1q_u32(weights.data()) &#8212; \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c 4 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u0437 \u043f\u0430\u043c\u044f\u0442\u0438 \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 weights.data() \u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u044b (ld \u2014 load)<\/p>\n<\/li>\n<li>\n<p>vandq_u32 \u2014 \u043f\u043e\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043d\u043e\u0435 &amp; (and)<\/p>\n<\/li>\n<li>\n<p>vaddvq_u32 \u2014 \u0441\u0443\u043c\u043c\u0430 \u0432\u0441\u0435\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430 (addv \u2014 add across vector)<\/p>\n<\/li>\n<\/ul>\n<h4>\u0421\u0442\u0440\u043e\u0438\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 index<\/h4>\n<p>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u044b \u043d\u0435\u043b\u044c\u0437\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u044c \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u043c\u0435\u0441\u0442\u043e uint8x16_t(\u0440\u0435\u0433\u0438\u0441\u0442\u0440 \u0438\u0437 16 uint8_t) \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c std::array&lt;uint8_t, 16&gt;. \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e idx \u0438\u0434\u0435\u043c \u043f\u043e 4 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c \u043c\u0430\u0441\u043a\u0438. \u0415\u0441\u043b\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432\u044b\u0431\u0440\u0430\u043d \u2014 \u0434\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043d\u043e\u043c\u0435\u0440\u0430 \u0435\u0433\u043e 4 \u0431\u0430\u0439\u0442 \u0432 index \u043d\u0430 \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u043a\u0443\u0440\u0441\u043e\u0440\u0430 \u0438 \u0441\u0434\u0432\u0438\u0433\u0430\u0435\u043c \u043a\u0443\u0440\u0441\u043e\u0440 \u043d\u0430 4.<\/p>\n<pre><code class=\"cpp\">consteval auto make_index_table() {    std::array&lt;std::array&lt;uint8_t, 16&gt;, 16&gt; index{};    for (size_t idx = 0; idx &lt; 16; ++idx) {      \/\/ \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u043c \u0432\u0441\u0435 \u043c\u0430\u0441\u043a\u0438        size_t j = 0;                               \/\/ j - \u043a\u0443\u0440\u0441\u043e\u0440        for (size_t i = 0; i &lt; 4; ++i)              \/\/ \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u043c\u0430\u0441\u043a\u0438            if (idx &amp; (1 &lt;&lt; i))                    \/\/ \u0435\u0441\u043b\u0438 i \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432\u044b\u0431\u0440\u0430\u043d                for (size_t k = 0; k &lt; 4; ++k)      \/\/ \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u043c \u0431\u0430\u0439\u0442\u044b \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430                    index[idx][j++] = i * 4 + k;     \/\/ \u043f\u0438\u0448\u0435\u043c \u043d\u043e\u043c\u0435\u0440\u0430 \u0435\u0433\u043e \u0431\u0430\u0439\u0442    }    return index;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041a\u0443\u0440\u0441\u043e\u0440 <code>j<\/code> \u0434\u0432\u0438\u0433\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0431\u0430\u0439\u0442\u044b \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u043b\u043e\u0436\u0430\u0442\u0441\u044f \u0432 index \u043f\u043e\u0434\u0440\u044f\u0434, \u0430 <code>tbl<\/code> \u043f\u043e index \u0441\u043e\u0431\u0435\u0440\u0435\u0442 float \u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440. \u041d\u0435\u0437\u0430\u043d\u044f\u0442\u044b\u0435 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0432 index \u2014 \u043d\u0443\u043b\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u0445\u0432\u043e\u0441\u0442\u0435, \u043f\u043e\u0441\u043b\u0435 count \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u0431\u0443\u0434\u0435\u0442 \u043c\u0443\u0441\u043e\u0440.<\/p>\n<h4>\u0422\u0430\u0431\u043b\u0438\u0446\u0430 count<\/h4>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0435\u0440\u0435\u043c. \u0422\u0430\u043a\u0438\u043c \u0436\u0435 \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u043e\u0441\u0447\u0438\u0442\u0430\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443:<\/p>\n<pre><code class=\"cpp\">consteval auto make_count_table() {    std::array&lt;uint8_t, 16&gt; count{};    for (size_t idx = 0; idx &lt; 16; ++idx)        for (size_t i = 0; i &lt; 4; ++i)            if (idx &amp; 1 &lt;&lt; i)                ++count[idx];    return count;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>Compress \u0446\u0435\u043b\u0438\u043a\u043e\u043c<\/h4>\n<pre><code class=\"cpp\">auto compress(uint32x4_t mask, float32x4_t a) {    static constexpr std::array&lt;uint32_t, 4&gt; weights{1, 2, 4, 8};    const size_t idx = vaddvq_u32(vandq_u32(mask, vld1q_u32(weights.data())));    static constexpr auto count = make_count_table();    static constexpr auto index_table = make_index_table();    const auto index = vld1q_u8(index_table[idx].data()); \/\/ \u0432 \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u0435 \u043e\u0434\u043d\u0443 \u0441\u0442\u0440\u043e\u043a\u0443 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0433\u0440\u0443\u0437\u0438\u043c \u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440    return std::pair{vreinterpretq_f32_u8(vqtbl1q_u8(vreinterpretq_u8_f32(a), index)), count[idx]};}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a tbl \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0441 u8, \u043d\u0430\u0434\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 <code>a<\/code> \u043f\u0435\u0440\u0435\u0432\u0435\u0441\u0442\u0438 \u0432 u8, \u0430 \u043f\u043e\u0442\u043e\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u0432 f32.<\/p>\n<p>\u0417\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0432 \u043f\u0430\u043c\u044f\u0442\u044c \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u043b\u043d\u044b\u043c\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u043c\u0438 \u2014 \u043f\u043e 4 float, \u0430 \u043a\u0443\u0440\u0441\u043e\u0440 \u0434\u0432\u0438\u0433\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 <code>cnt<\/code>. Compress \u043a\u043b\u0430\u0434\u0435\u0442 \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0432 \u043d\u0430\u0447\u0430\u043b\u043e \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430, \u0442\u043e \u0435\u0441\u0442\u044c [j, j + cnt), \u0430 \u0432 [j + cnt, j + 4) \u2014 \u043c\u0443\u0441\u043e\u0440. \u0410 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044f \u043d\u0430\u0447\u043d\u0435\u0442\u0441\u044f \u0441 j + count, \u0442\u043e \u0435\u0441\u0442\u044c \u0437\u0430\u0442\u0440\u0435\u0442 \u043c\u0443\u0441\u043e\u0440 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e \u0448\u0430\u0433\u0430. \u041c\u0443\u0441\u043e\u0440 \u043e\u0441\u0442\u0430\u043d\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e store \u0432 <code>out[cnt, n)<\/code>, \u0430 \u0437\u0430 \u0433\u0440\u0430\u043d\u0438\u0446\u044b <code>out[0, n)<\/code> \u043d\u0435 \u0432\u044b\u0445\u043e\u0434\u0438\u043c \u2014 \u043a\u0443\u0440\u0441\u043e\u0440 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u043e\u0431\u0433\u043e\u043d\u044f\u0435\u0442 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043d\u043d\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b.<\/p>\n<h3>\u0426\u0438\u043a\u043b copy_if<\/h3>\n<pre><code class=\"cpp\">auto copy_if_neon(const float* __restrict a,                  float* __restrict out,                  float threshold,                  size_t n) {    auto thd = vdupq_n_f32(threshold);          \/\/ \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c threshold \u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440    size_t j = 0;     for (size_t i = 0; i &lt; n; i += 4) {        auto v = vld1q_f32(a + i);              \/\/ \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0438\u0435 4 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 a \u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440        auto mask = vcgtq_f32(v, thd);          \/\/ \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u043c\u0430\u0441\u043a\u0443 \u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0445        auto [packed, cnt] = compress(mask, v);        vst1q_f32(out + j, packed);             \/\/ \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c packed \u0432 out[j, j + 4), \u0432 [j + cnt, j + 4) \u0431\u0443\u0434\u0435\u0442 \u043c\u0443\u0441\u043e\u0440         j += cnt;     }    return j;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u2014 vcgtq_f32(v, thd) \u2014 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043d\u043e\u0433\u043e v[i] &gt; thd[i]. <code>cgt<\/code> \u2014 compare greater \u2014 vst1q_f32 \u2014 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0432 \u043f\u0430\u043c\u044f\u0442\u044c 4 float \u0438\u0437 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430. <code>st<\/code> \u2014 store<\/p>\n<h3>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/h3>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u0424\u0443\u043d\u043a\u0446\u0438\u044f<\/p>\n<\/th>\n<th>\n<p align=\"left\">ms (cache)<\/p>\n<\/th>\n<th>\n<p align=\"left\">GB\/s (cache)<\/p>\n<\/th>\n<th>\n<p align=\"left\">ms (DRAM)<\/p>\n<\/th>\n<th>\n<p align=\"left\">GB\/s (DRAM)<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">copy a[i] if a[i] &gt; 0<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.0104<\/p>\n<\/td>\n<td>\n<p align=\"left\">77<\/p>\n<\/td>\n<td>\n<p align=\"left\">1.11<\/p>\n<\/td>\n<td>\n<p align=\"left\">72<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">copy a[i] if a[i] &gt; 0.5<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.01063<\/p>\n<\/td>\n<td>\n<p align=\"left\">75<\/p>\n<\/td>\n<td>\n<p align=\"left\">1.13<\/p>\n<\/td>\n<td>\n<p align=\"left\">71<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">copy a[i] if a[i] &gt; 1<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.01<\/p>\n<\/td>\n<td>\n<p align=\"left\">80<\/p>\n<\/td>\n<td>\n<p align=\"left\">1.06<\/p>\n<\/td>\n<td>\n<p align=\"left\">76<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>&gt; 0.5 \u0434\u043b\u044f \u0441\u043a\u0430\u043b\u044f\u0440\u0430 \u0431\u044b\u043b \u0445\u0443\u0434\u0448\u0438\u043c \u0441\u043b\u0443\u0447\u0430\u0435\u043c. 3 GB\/s. \u0421\u0442\u0430\u043b\u043e 71 GB\/s. \u041f\u0440\u0438\u0440\u043e\u0441\u0442 \u0431\u043e\u043b\u0435\u0435 \u0447\u0435\u043c \u0432 20 \u0440\u0430\u0437. \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0435\u0442 \u0432\u0435\u0442\u043e\u043a, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<h3>\u0422\u0440\u044e\u043a 2: \u0421\u0447\u0438\u0442\u0430\u0435\u043c idx \u0438 count \u0437\u0430 \u043e\u0434\u0438\u043d addv<\/h3>\n<p><code>idx<\/code> \u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u0435\u043d\u044c\u0448\u0435 16, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u0434\u0435\u043b\u0430\u0435\u043c weights = {1 + 16, 2 + 16, 4 + 16, 8 + 16} \u0438 \u0442\u043e\u0433\u0434\u0430 s = (\u0441\u0443\u043c\u043c\u0430 \u0432\u043d\u0443\u0442\u0440\u0438 mask &amp; weights) \/ 16 \u0434\u0430\u0441\u0442 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u0430 s % 16 \u2014 \u0441\u0430\u043c <code>idx<\/code>. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u0436\u043d\u043e \u043d\u0435 \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 count, \u0438 \u0442\u0435\u043f\u0435\u0440\u044c compress:<\/p>\n<pre><code class=\"cpp\">auto compress(uint32x4_t mask, float32x4_t a) {    static constexpr std::array&lt;uint32_t, 4&gt; weights{1 + 16, 2 + 16, 4 + 16, 8 + 16};    const size_t s = vaddvq_u32(vandq_u32(mask, vld1q_u32(weights.data())));    const size_t count = s &gt;&gt; 4; \/\/ \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435, \u0447\u0442\u043e \u0438 s \/ 16    const size_t idx = s &amp; 15;   \/\/ \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435, \u0447\u0442\u043e \u0438 s % 16        static constexpr auto index_table = make_index_table();        const auto index = vld1q_u8(index_table[idx].data());    return std::pair{vreinterpretq_f32_u8(vqtbl1q_u8(vreinterpretq_u8_f32(a), index)), count};}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0418 \u0442\u0435\u043f\u0435\u0440\u044c \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u0435\u0449\u0435:<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u0424\u0443\u043d\u043a\u0446\u0438\u044f<\/p>\n<\/th>\n<th>\n<p align=\"left\">ms (cache)<\/p>\n<\/th>\n<th>\n<p align=\"left\">GB\/s (cache)<\/p>\n<\/th>\n<th>\n<p align=\"left\">ms (DRAM)<\/p>\n<\/th>\n<th>\n<p align=\"left\">GB\/s (DRAM)<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">copy a[i] if a[i] &gt; 0<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.0095<\/p>\n<\/td>\n<td>\n<p align=\"left\">84<\/p>\n<\/td>\n<td>\n<p align=\"left\">1.015<\/p>\n<\/td>\n<td>\n<p align=\"left\">79<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">copy a[i] if a[i] &gt; 0.5<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.0095<\/p>\n<\/td>\n<td>\n<p align=\"left\">84<\/p>\n<\/td>\n<td>\n<p align=\"left\">1.007<\/p>\n<\/td>\n<td>\n<p align=\"left\">79<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">copy a[i] if a[i] &gt; 1<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.0096<\/p>\n<\/td>\n<td>\n<p align=\"left\">83<\/p>\n<\/td>\n<td>\n<p align=\"left\">1.008<\/p>\n<\/td>\n<td>\n<p align=\"left\">79<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<h3>Unroll<\/h3>\n<p>\u0415\u0449\u0435 \u043c\u043e\u0436\u043d\u043e \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0432\u044b\u0436\u0430\u0442\u044c \u0440\u0430\u0437\u0432\u043e\u0440\u043e\u0442\u043e\u043c \u0446\u0438\u043a\u043b\u0430 \u043f\u043e 4 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438 (16 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432), \u0447\u0438\u0441\u043b\u0430:<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u0424\u0443\u043d\u043a\u0446\u0438\u044f<\/p>\n<\/th>\n<th>\n<p align=\"left\">ms (cache)<\/p>\n<\/th>\n<th>\n<p align=\"left\">GB\/s (cache)<\/p>\n<\/th>\n<th>\n<p align=\"left\">ms (DRAM)<\/p>\n<\/th>\n<th>\n<p align=\"left\">GB\/s (DRAM)<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">copy a[i] if a[i] &gt; 0<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.0081<\/p>\n<\/td>\n<td>\n<p align=\"left\">98<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.882<\/p>\n<\/td>\n<td>\n<p align=\"left\">91<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">copy a[i] if a[i] &gt; 0.5<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.0083<\/p>\n<\/td>\n<td>\n<p align=\"left\">97<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.892<\/p>\n<\/td>\n<td>\n<p align=\"left\">90<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">copy a[i] if a[i] &gt; 1<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.0082<\/p>\n<\/td>\n<td>\n<p align=\"left\">97<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.869<\/p>\n<\/td>\n<td>\n<p align=\"left\">92<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u043a\u043e\u0434:<\/p>\n<pre><code class=\"cpp\">consteval auto make_index_table() {    std::array&lt;std::array&lt;uint8_t, 16&gt;, 16&gt; index{};    for (size_t idx = 0; idx &lt; 16; ++idx) {        size_t j = 0;        for (size_t i = 0; i &lt; 4; ++i)            if (idx &amp; (1 &lt;&lt; i))                for (size_t k = 0; k &lt; 4; ++k)                    index[idx][j++] = i * 4 + k;    }    return index;}auto compress(uint32x4_t mask, float32x4_t a) {    static constexpr std::array&lt;uint32_t, 4&gt; weights{1 + 16, 2 + 16, 4 + 16, 8 + 16};    const size_t s = vaddvq_u32(vandq_u32(mask, vld1q_u32(weights.data())));    const size_t count = s &gt;&gt; 4;    const size_t idx = s &amp; 15;        static constexpr auto index_table = make_index_table();        const auto index = vld1q_u8(index_table[idx].data());    return std::pair{vreinterpretq_f32_u8(vqtbl1q_u8(vreinterpretq_u8_f32(a), index)), count};}auto copy_if_neon_unroll(const float* __restrict a,                          float* __restrict out,                          float threshold,                          size_t n) {    auto thd = vdupq_n_f32(threshold);    size_t j = 0;    size_t i = 0;    for (; i + 16 &lt;= n; i += 16) {#pragma unroll        for (size_t i0 = 0; i0 &lt; 16; i0 += 4) {            auto v = vld1q_f32(a + i + i0);            auto mask = vcgtq_f32(v, thd);            auto [packed, cnt] = compress(mask, v);            vst1q_f32(out + j, packed);            j += cnt;        }    }    for (; i + 4 &lt;= n; i += 4) {        auto v = vld1q_f32(a + i);        auto mask = vcgtq_f32(v, thd);        auto [packed, cnt] = compress(mask, v);        vst1q_f32(out + j, packed);        j += cnt;    }    return j;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>tbl<\/code> \u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u0430 \u0438\u043d\u0434\u0435\u043a\u0441\u043e\u0432 \u0434\u0430\u044e\u0442 \u0442\u043e, \u0447\u0435\u0433\u043e \u0432 NEON \u043d\u0435\u0442 \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u2014 compress. \u0418 \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e &gt;threshold: \u0442\u0430\u043a \u0436\u0435 \u0434\u0435\u043b\u0430\u044e\u0442\u0441\u044f filter, remove \u0438 \u043f\u0440\u043e\u0447\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0433\u0434\u0435 \u0432\u044b\u0445\u043e\u0434 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1055904\/\">https:\/\/habr.com\/ru\/articles\/1055904\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u0417\u0430\u0434\u0430\u0447\u0430\u0414\u0430\u043d\u044b \u043c\u0430\u0441\u0441\u0438\u0432\u044b a \u0438 out. \u041d\u0443\u0436\u043d\u043e \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0432 out \u043f\u043e\u0434\u0440\u044f\u0434, \u0431\u0435\u0437 \u043f\u0440\u043e\u0431\u0435\u043b\u043e\u0432, \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b a, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u044e\u0442 \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u0443\u0441\u043b\u043e\u0432\u0438\u044e. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u2014 \u0443\u0441\u043b\u043e\u0432\u0438\u0435 a[i] &gt; threshold, a[i] \u2208 (0, 1), threshold \u2208 {0, 0.5, 1}.\u041f\u043e\u0447\u0435\u043c\u0443 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u0441\u0434\u0430\u0435\u0442\u0441\u044f\u041e\u0434\u0438\u043d if \u0432\u043d\u0443\u0442\u0440\u0438 \u0446\u0438\u043a\u043b\u0430 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u043e\u043d\u044f\u0435\u0442 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0441 112 \u0434\u043e 2.6 GB\/s. \u041a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0432\u0435\u043a\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u2014 \u0432 NEON \u043d\u0435\u0442 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0435\u0439 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438. \u0421\u0442\u0430\u0442\u044c\u044f \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0435\u0435.auto copy_if(const float* a, float* out, size_t n) {    size_t j = 0;    for (size_t i = 0; i &lt; n; ++i) {        if (a[i] &gt; 0) out[j++] = a[i];    }    return j;}\u0412 \u0437\u0430\u0434\u0430\u0447\u0435 copy_if \u0432\u044b\u0445\u043e\u0434\u043d\u043e\u0439 \u043a\u0443\u0440\u0441\u043e\u0440 (\u0432 \u043a\u043e\u0434\u0435 &#8212; j) \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u043e\u044d\u0442\u043e\u043c\u0443, \u0447\u0442\u043e\u0431\u044b \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u0432\u0435\u043a\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043b, \u043d\u0443\u0436\u043d\u0430 compress-\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f (\u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430 \u043f\u043e\u0434\u0440\u044f\u0434 \u0432 \u0435\u0433\u043e \u043d\u0430\u0447\u0430\u043b\u043e, \u0431\u0435\u0437 \u0434\u044b\u0440\u043e\u043a), \u0430 \u0432 NEON \u0435\u0435 \u043d\u0435\u0442, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u0441\u0434\u0430\u0435\u0442\u0441\u044f:clang++ -O3 -Rpass-analysis=loop-vectorize -std=c++23 main.cpp -o mainmain.cpp:5:5: remark: loop not vectorized: value that could not be identified as reduction is used outside the loop [-Rpass-analysis=loop-vectorize]5 | for (size_t i = 0; i &lt; n; ++i) {| ^main.cpp:6:23: remark: loop not vectorized: cannot identify array bounds [-Rpass-analysis=loop-vectorize]6 | if (a[i] &gt; 0) out[j++] = a[i];\u0412\u0435\u043a\u0442\u043e\u0440\u0438\u0437\u0430\u0442\u043e\u0440 clang \u0443\u043c\u0435\u0435\u0442 \u043a\u043b\u0430\u0441\u0441\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c j \u043b\u0438\u0431\u043e \u043a\u0430\u043a induction (\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0448\u0430\u0433), \u043b\u0438\u0431\u043e \u043a\u0430\u043a reduction (\u0441\u0432\u0435\u0440\u0442\u043a\u0430). j \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0438 \u0442\u0435\u043c, \u043d\u0438 \u0434\u0440\u0443\u0433\u0438\u043c \u2014 \u043e\u043d \u043a\u0443\u0440\u0441\u043e\u0440, \u0437\u0430\u0432\u0438\u0441\u044f\u0449\u0438\u0439 \u043e\u0442 \u0434\u0430\u043d\u043d\u044b\u0445. \u041a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u043d\u0435 \u0443\u043c\u0435\u0435\u0442 \u0432\u0435\u043a\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u0432\u0438\u0434 \u043a\u0443\u0440\u0441\u043e\u0440\u043e\u0432. \u0412\u0442\u043e\u0440\u0430\u044f \u0440\u0435\u043c\u0430\u0440\u043a\u0430 \u043e\u0442\u0441\u044e\u0434\u0430 \u0436\u0435: \u043e\u043d \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u044c \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0439 \u043a out.\u0417\u0430\u043c\u0435\u0440: \u0434\u0432\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0441\u043a\u0430\u043b\u044f\u0440\u0430\u0432\u0441\u0435 \u0437\u0430\u043c\u0435\u0440\u044b: Apple M5; clang++ -O3 -std=c++23 -march=native; GB\/s = (2n * 4 \u0431\u0430\u0439\u0442\u0430) \/ \u0432\u0440\u0435\u043c\u044f, \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0438\u0437 3e9 \/ n \u043f\u0440\u043e\u0433\u043e\u043d\u043e\u0432; cache: n=1e5, DRAM: n=1e7\u0424\u0443\u043d\u043a\u0446\u0438\u044fms (cache)GB\/s (cache)ms (DRAM)GB\/s (DRAM)copy a[i]0.0041950.71112copy a[i] if a[i] &gt; 00.022372.4133copy a[i] if a[i] &gt; 0.50.2583.130.612.6copy a[i] if a[i] &gt; 10.021372.3933\u201ccopy a[i]\u201d \u2014 \u0442\u043e\u0442 \u0436\u0435 \u0446\u0438\u043a\u043b, \u043d\u043e \u0431\u0435\u0437 \u0443\u0441\u043b\u043e\u0432\u0438\u044f, \u0435\u0433\u043e \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u0432\u0435\u043a\u0442\u043e\u0440\u0438\u0437\u0443\u0435\u0442. \u0412\u0441\u044f \u0440\u0430\u0437\u043d\u0438\u0446\u0430 \u0441 \u043d\u0438\u043c \u0432 \u043e\u0434\u043d\u043e\u043c if. \u0414\u0430\u043d\u043d\u044b\u0435 \u0442\u0435 \u0436\u0435, \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u043e\u0441\u0442\u044c \u0432\u0435\u0442\u043a\u0438:&gt; 0 (\u0432\u0441\u0435\u0433\u0434\u0430 true) \u0438 &gt; 1 (\u0432\u0441\u0435\u0433\u0434\u0430 false): branch predictor \u043d\u0435 \u043f\u0440\u043e\u043c\u0430\u0445\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u2192 33 GB\/s. \u0418\u0437-\u0437\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u044f \u0432\u0435\u043a\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043f\u0430\u0434\u0430\u0435\u0442 \u0432 3 \u0440\u0430\u0437\u0430&gt; 0.5 (50\/50): \u043f\u0440\u043e\u043c\u0430\u0445 \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0432\u0442\u043e\u0440\u043e\u043c \u2192 3 GB\/s\u0422\u0440\u044e\u043a \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442 \u043e\u0431\u0435 \u044d\u0442\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b.\u0422\u0440\u044e\u043a 1: \u044d\u043c\u0443\u043b\u0438\u0440\u0443\u0435\u043c compress\u0414\u0430\u043b\u044c\u0448\u0435 \u0441\u0447\u0438\u0442\u0430\u0435\u043c n \u043a\u0440\u0430\u0442\u043d\u044b\u043c \u0448\u0438\u0440\u0438\u043d\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430; \u0445\u0432\u043e\u0441\u0442 \u2014 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u0442\u0435\u043c\u0430, \u043a \u0442\u0440\u044e\u043a\u0443 \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u044f \u043d\u0435 \u0438\u043c\u0435\u0435\u0442. \u0415\u0449\u0435:\u0420\u0430\u0437\u043c\u0435\u0440 out \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c &gt;= n.\u041f\u0443\u0441\u0442\u044c \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0432\u044b\u0431\u0440\u0430\u043b cnt \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u0442\u043e\u0433\u0434\u0430 \u0432\u0441\u0435 \u0432 out[cnt, n) \u0431\u0443\u0434\u0435\u0442 \u043d\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043e (\u043c\u0443\u0441\u043e\u0440). \u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c, \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0449\u0438\u0439 \u0447\u0438\u0441\u0442\u043e\u0442\u0443 \u0445\u0432\u043e\u0441\u0442\u0430, \u043d\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043a \u0438\u0434\u0435\u0435 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u043e\u0432\u043e\u0433\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u0442\u0441\u044f.\u0412 NEON \u043d\u0435\u0442 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0441\u0436\u0430\u0442\u0438\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u044d\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0435.(\u0421\u0442\u043e\u0438\u0442 \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u0441\u0430\u043c \u043f\u0440\u0438\u0451\u043c \u2014 \u043d\u0435 \u043d\u043e\u0432\u044b\u0439. \u041b\u0435\u043c\u0438\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0435\u0433\u043e \u0435\u0449\u0435 \u0432 2017 \u0433\u043e\u0434\u0443 \u043d\u0430 SSE link. \u041d\u043e \u043d\u0430 NEON \u043d\u0435\u0442 \u043d\u0438 movemask, \u043d\u0438 \u0434\u0435\u0448\u0435\u0432\u043e\u0433\u043e popcnt &#8212; \u0434\u0430\u043b\u044c\u0448\u0435 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0435 \u044d\u0442\u043e \u0438\u0437 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0435\u0441\u0442\u044c)\u0427\u0442\u043e \u0434\u043e\u043b\u0436\u0435\u043d \u0443\u043c\u0435\u0442\u044c \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0430\u0448 \u0430\u043d\u0430\u043b\u043e\u0433 compress:\u041f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0440\u0435\u0433\u0438\u0441\u0442\u0440 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 a \u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440-\u043c\u0430\u0441\u043a\u0443, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0431\u043e\u0440.\u0421\u043a\u0430\u0437\u0430\u0442\u044c, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0438\u0437 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430 \u043c\u044b \u0432\u0437\u044f\u043b\u0438 (\u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c out).\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0432 out.tbl: \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u0430\u044f \u0432\u044b\u0431\u043e\u0440\u043a\u0430 \u0431\u0430\u0439\u0442\u0412 NEON \u0435\u0441\u0442\u044c \u0441\u0435\u043c\u0435\u0439\u0441\u0442\u0432\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0439 table-lookup (tbl), \u0438\u0445 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u2014 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u0430\u044f \u0432\u044b\u0431\u043e\u0440\u043a\u0430\/\u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0431\u0430\u0439\u0442. \u0418\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0434\u0432\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430:\u0422\u0430\u0431\u043b\u0438\u0446\u0430 (table) \u2014 \u0431\u0430\u0439\u0442\u044b, \u043e\u0442\u043a\u0443\u0434\u0430 \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c.\u0418\u043d\u0434\u0435\u043a\u0441\u044b (index) \u2014 \u043d\u043e\u043c\u0435\u0440\u0430 \u0431\u0430\u0439\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0443\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c.\u041f\u0440\u043e\u0449\u0435 \u0433\u043e\u0432\u043e\u0440\u044f \u2014 \u044d\u0442\u043e SIMD-\u0430\u043d\u0430\u043b\u043e\u0433 out[i] = table[index[i]].\u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044e vqtbl1q_u8:\u0447\u0430\u0441\u0442\u044c\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435vvector intrinsicq\u0442\u0430\u0431\u043b\u0438\u0446\u0430 &#8212; \u0438\u0437 128-\u0431\u0438\u0442\u043d\u044b\u0445 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u043e\u0432tbltable lookup1\u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u043e\u0432 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435q\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0438 \u0438\u043d\u0434\u0435\u043a\u0441\u044b &#8212; 128-\u0431\u0438\u0442\u043d\u044b\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u044bu8\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0442\u0430\u0431\u043b\u0438\u0446\u044b &#8212; uint8_ttbl \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0431\u0430\u0439\u0442\u044b, \u0430 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u0442\u044c float (4 \u0431\u0430\u0439\u0442\u0430). \u0417\u043d\u0430\u0447\u0438\u0442, index \u0431\u0443\u0434\u0435\u043c \u0434\u0435\u043b\u0430\u0442\u044c \u0431\u043b\u043e\u043a\u0430\u043c\u0438 \u043f\u043e 4 \u0431\u0430\u0439\u0442\u0430: \u0447\u0442\u043e\u0431\u044b \u0432\u0437\u044f\u0442\u044c \u0432\u0442\u043e\u0440\u043e\u0439 (0-based) float \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430, \u0432 index \u043f\u043e\u0439\u0434\u0443\u0442 \u0435\u0433\u043e \u0431\u0430\u0439\u0442\u044b [8, 9, 10, 11] (\u0432\u0442\u043e\u0440\u043e\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441\u043e \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u044f 2 *sizeof(float) = 8).\u0421\u0447\u0438\u0442\u0430\u0442\u044c index \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u0434\u043e\u043b\u0433\u043e. \u0412\u0441\u0435\u0433\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 16 (4 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0432\u0437\u044f\u0442\u044c\/\u0432\u044b\u043a\u0438\u043d\u0443\u0442\u044c), \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u0441\u0447\u0438\u0442\u0430\u0435\u043c \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0432\u0441\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b index. \u041d\u043e \u0447\u0442\u043e\u0431\u044b \u043f\u043e \u043c\u0430\u0441\u043a\u0435 \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c index, \u043d\u0430\u0434\u043e \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u043c\u0430\u0441\u043a\u0443 \u0432 \u0447\u0438\u0441\u043b\u043e (\u043d\u0430\u0437\u043e\u0432\u0435\u043c \u0435\u0433\u043e idx):\u041c\u0430\u0441\u043a\u0430 \u2192 idx\u041c\u0430\u0441\u043a\u0430 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 4 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u043a\u0430\u0436\u0434\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u2014 \u043b\u0438\u0431\u043e 0x00000000 (false), \u043b\u0438\u0431\u043e 0xFFFFFFFF (true). \u0425\u043e\u0442\u0438\u043c: \u0435\u0441\u043b\u0438 i-\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 true \u2014 \u0432\u044b\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432 idx i-\u0439 \u0431\u0438\u0442. \u0422\u0440\u044e\u043a: mask &amp; [1, 2, 4, 8]. \u0422\u0430\u043a \u043a\u0430\u043a 0xFFFFFFFF &amp; x = x, \u0432 \u0438\u0441\u0442\u0438\u043d\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0445 \u043e\u0441\u0442\u0430\u043d\u0435\u0442\u0441\u044f \u0432\u0435\u0441 (1\/2\/4\/8), \u0430 \u0432 \u043b\u043e\u0436\u043d\u044b\u0445 0. \u0421\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u043c \u0432\u0441\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u0431\u043e\u0439 \u2014 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0447\u0438\u0441\u043b\u043e 0\u202615.std::array&lt;uint32_t, 4&gt; weights{1, 2, 4, 8};size_t idx = vaddvq_u32(vandq_u32(mask, vld1q_u32(weights.data())));vld1q_u32(weights.data()) &#8212; \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c 4 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u0437 \u043f\u0430\u043c\u044f\u0442\u0438 \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 weights.data() \u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u044b (ld \u2014 load)vandq_u32 \u2014 \u043f\u043e\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043d\u043e\u0435 &amp; (and)vaddvq_u32 \u2014 \u0441\u0443\u043c\u043c\u0430 \u0432\u0441\u0435\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430 (addv \u2014 add across vector)\u0421\u0442\u0440\u043e\u0438\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 index\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u044b \u043d\u0435\u043b\u044c\u0437\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u044c \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u043c\u0435\u0441\u0442\u043e uint8x16_t(\u0440\u0435\u0433\u0438\u0441\u0442\u0440 \u0438\u0437 16 uint8_t) \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c std::array&lt;uint8_t, 16&gt;. \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e idx \u0438\u0434\u0435\u043c \u043f\u043e 4 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c \u043c\u0430\u0441\u043a\u0438. \u0415\u0441\u043b\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432\u044b\u0431\u0440\u0430\u043d \u2014 \u0434\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043d\u043e\u043c\u0435\u0440\u0430 \u0435\u0433\u043e 4 \u0431\u0430\u0439\u0442 \u0432 index \u043d\u0430 \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u043a\u0443\u0440\u0441\u043e\u0440\u0430 \u0438 \u0441\u0434\u0432\u0438\u0433\u0430\u0435\u043c \u043a\u0443\u0440\u0441\u043e\u0440 \u043d\u0430 4.consteval auto make_index_table() {    std::array&lt;std::array&lt;uint8_t, 16&gt;, 16&gt; index{};    for (size_t idx = 0; idx &lt; 16; ++idx) {      \/\/ \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u043c \u0432\u0441\u0435 \u043c\u0430\u0441\u043a\u0438        size_t j = 0;                               \/\/ j &#8212; \u043a\u0443\u0440\u0441\u043e\u0440        for (size_t i = 0; i &lt; 4; ++i)              \/\/ \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u043c\u0430\u0441\u043a\u0438            if (idx &amp; (1 &lt;&lt; i))                    \/\/ \u0435\u0441\u043b\u0438 i \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432\u044b\u0431\u0440\u0430\u043d                for (size_t k = 0; k &lt; 4; ++k)      \/\/ \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u043c \u0431\u0430\u0439\u0442\u044b \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430                    index[idx][j++] = i * 4 + k;     \/\/ \u043f\u0438\u0448\u0435\u043c \u043d\u043e\u043c\u0435\u0440\u0430 \u0435\u0433\u043e \u0431\u0430\u0439\u0442    }    return index;}\u041a\u0443\u0440\u0441\u043e\u0440 j \u0434\u0432\u0438\u0433\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0431\u0430\u0439\u0442\u044b \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u043b\u043e\u0436\u0430\u0442\u0441\u044f \u0432 index \u043f\u043e\u0434\u0440\u044f\u0434, \u0430 tbl \u043f\u043e index \u0441\u043e\u0431\u0435\u0440\u0435\u0442 float \u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440. \u041d\u0435\u0437\u0430\u043d\u044f\u0442\u044b\u0435 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0432 index \u2014 \u043d\u0443\u043b\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u0445\u0432\u043e\u0441\u0442\u0435, \u043f\u043e\u0441\u043b\u0435 count \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u0431\u0443\u0434\u0435\u0442 \u043c\u0443\u0441\u043e\u0440.\u0422\u0430\u0431\u043b\u0438\u0446\u0430 count\u0414\u0430\u043b\u044c\u0448\u0435 \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0435\u0440\u0435\u043c. \u0422\u0430\u043a\u0438\u043c \u0436\u0435 \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u043e\u0441\u0447\u0438\u0442\u0430\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443:consteval auto make_count_table() {    std::array&lt;uint8_t, 16&gt; count{};    for (size_t idx = 0; idx &lt; 16; ++idx)        for (size_t i = 0; i &lt; 4; ++i)            if (idx &amp; 1 &lt;&lt; i)                ++count[idx];    return count;}Compress \u0446\u0435\u043b\u0438\u043a\u043e\u043cauto compress(uint32x4_t mask, float32x4_t a) {    static constexpr std::array&lt;uint32_t, 4&gt; weights{1, 2, 4, 8};    const size_t idx = vaddvq_u32(vandq_u32(mask, vld1q_u32(weights.data())));    static constexpr auto count = make_count_table();    static constexpr auto index_table = make_index_table();    const auto index = vld1q_u8(index_table[idx].data()); \/\/ \u0432 \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u0435 \u043e\u0434\u043d\u0443 \u0441\u0442\u0440\u043e\u043a\u0443 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0433\u0440\u0443\u0437\u0438\u043c \u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440    return std::pair{vreinterpretq_f32_u8(vqtbl1q_u8(vreinterpretq_u8_f32(a), index)), count[idx]};}\u0422\u0430\u043a \u043a\u0430\u043a tbl \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0441 u8, \u043d\u0430\u0434\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 a \u043f\u0435\u0440\u0435\u0432\u0435\u0441\u0442\u0438 \u0432 u8, \u0430 \u043f\u043e\u0442\u043e\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u0432 f32.\u0417\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0432 \u043f\u0430\u043c\u044f\u0442\u044c \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u043b\u043d\u044b\u043c\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u043c\u0438 \u2014 \u043f\u043e 4 float, \u0430 \u043a\u0443\u0440\u0441\u043e\u0440 \u0434\u0432\u0438\u0433\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 cnt. Compress \u043a\u043b\u0430\u0434\u0435\u0442 \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0432 \u043d\u0430\u0447\u0430\u043b\u043e \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430, \u0442\u043e \u0435\u0441\u0442\u044c [j, j + cnt), \u0430 \u0432 [j + cnt, j + 4) \u2014 \u043c\u0443\u0441\u043e\u0440. \u0410 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044f \u043d\u0430\u0447\u043d\u0435\u0442\u0441\u044f \u0441 j + count, \u0442\u043e \u0435\u0441\u0442\u044c \u0437\u0430\u0442\u0440\u0435\u0442 \u043c\u0443\u0441\u043e\u0440 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e \u0448\u0430\u0433\u0430. \u041c\u0443\u0441\u043e\u0440 \u043e\u0441\u0442\u0430\u043d\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e store \u0432 out[cnt, n), \u0430 \u0437\u0430 \u0433\u0440\u0430\u043d\u0438\u0446\u044b out[0, n) \u043d\u0435 \u0432\u044b\u0445\u043e\u0434\u0438\u043c \u2014 \u043a\u0443\u0440\u0441\u043e\u0440 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u043e\u0431\u0433\u043e\u043d\u044f\u0435\u0442 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043d\u043d\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b.\u0426\u0438\u043a\u043b copy_ifauto copy_if_neon(const float* __restrict a,                  float* __restrict out,                  float threshold,                  size_t n) {    auto thd = vdupq_n_f32(threshold);          \/\/ \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c threshold \u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440    size_t j = 0;     for (size_t i = 0; i &lt; n; i += 4) {        auto v = vld1q_f32(a + i);              \/\/ \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0438\u0435 4 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 a \u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440        auto mask = vcgtq_f32(v, thd);          \/\/ \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u043c\u0430\u0441\u043a\u0443 \u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0445        auto [packed, cnt] = compress(mask, v);        vst1q_f32(out + j, packed);             \/\/ \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c packed \u0432 out[j, j + 4), \u0432 [j + cnt, j + 4) \u0431\u0443\u0434\u0435\u0442 \u043c\u0443\u0441\u043e\u0440         j += cnt;     }    return j;}\u2014 vcgtq_f32(v, thd) \u2014 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043d\u043e\u0433\u043e v[i] &gt; thd[i]. cgt \u2014 compare greater \u2014 vst1q_f32 \u2014 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0432 \u043f\u0430\u043c\u044f\u0442\u044c 4 float \u0438\u0437 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430. st \u2014 store\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0424\u0443\u043d\u043a\u0446\u0438\u044fms (cache)GB\/s (cache)ms (DRAM)GB\/s (DRAM)copy a[i] if a[i] &gt; 00.0104771.1172copy a[i] if a[i] &gt; 0.50.01063751.1371copy a[i] if a[i] &gt; 10.01801.0676&gt; 0.5 \u0434\u043b\u044f \u0441\u043a\u0430\u043b\u044f\u0440\u0430 \u0431\u044b\u043b \u0445\u0443\u0434\u0448\u0438\u043c \u0441\u043b\u0443\u0447\u0430\u0435\u043c. 3 GB\/s. \u0421\u0442\u0430\u043b\u043e 71 GB\/s. \u041f\u0440\u0438\u0440\u043e\u0441\u0442 \u0431\u043e\u043b\u0435\u0435 \u0447\u0435\u043c \u0432 20 \u0440\u0430\u0437. \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0435\u0442 \u0432\u0435\u0442\u043e\u043a, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0434\u0430\u043d\u043d\u044b\u0445.\u0422\u0440\u044e\u043a 2: \u0421\u0447\u0438\u0442\u0430\u0435\u043c idx \u0438 count \u0437\u0430 \u043e\u0434\u0438\u043d addvidx \u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u0435\u043d\u044c\u0448\u0435 16, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u0434\u0435\u043b\u0430\u0435\u043c weights = {1 + 16, 2 + 16, 4 + 16, 8 + 16} \u0438 \u0442\u043e\u0433\u0434\u0430 s = (\u0441\u0443\u043c\u043c\u0430 \u0432\u043d\u0443\u0442\u0440\u0438 mask &amp; weights) \/ 16 \u0434\u0430\u0441\u0442 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u0430 s % 16 \u2014 \u0441\u0430\u043c idx. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u0436\u043d\u043e \u043d\u0435 \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 count, \u0438 \u0442\u0435\u043f\u0435\u0440\u044c compress:auto compress(uint32x4_t mask, float32x4_t a) {    static constexpr std::array&lt;uint32_t, 4&gt; weights{1 + 16, 2 + 16, 4 + 16, 8 + 16};    const size_t s = vaddvq_u32(vandq_u32(mask, vld1q_u32(weights.data())));    const size_t count = s &gt;&gt; 4; \/\/ \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435, \u0447\u0442\u043e \u0438 s \/ 16    const size_t idx = s &amp; 15;   \/\/ \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435, \u0447\u0442\u043e \u0438 s % 16        static constexpr auto index_table = make_index_table();        const auto index = vld1q_u8(index_table[idx].data());    return std::pair{vreinterpretq_f32_u8(vqtbl1q_u8(vreinterpretq_u8_f32(a), index)), count};}\u0418 \u0442\u0435\u043f\u0435\u0440\u044c \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u0435\u0449\u0435:\u0424\u0443\u043d\u043a\u0446\u0438\u044fms (cache)GB\/s (cache)ms (DRAM)GB\/s (DRAM)copy a[i] if a[i] &gt; 00.0095841.01579copy a[i] if a[i] &gt; 0.50.0095841.00779copy a[i] if a[i] &gt; 10.0096831.00879Unroll\u0415\u0449\u0435 \u043c\u043e\u0436\u043d\u043e \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0432\u044b\u0436\u0430\u0442\u044c \u0440\u0430\u0437\u0432\u043e\u0440\u043e\u0442\u043e\u043c \u0446\u0438\u043a\u043b\u0430 \u043f\u043e 4 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438 (16 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432), \u0447\u0438\u0441\u043b\u0430:\u0424\u0443\u043d\u043a\u0446\u0438\u044fms (cache)GB\/s (cache)ms (DRAM)GB\/s (DRAM)copy a[i] if a[i] &gt; 00.0081980.88291copy a[i] if a[i] &gt; 0.50.0083970.89290copy a[i] if a[i] &gt; 10.0082970.86992\u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u043a\u043e\u0434:consteval auto make_index_table() {    std::array&lt;std::array&lt;uint8_t, 16&gt;, 16&gt; index{};    for (size_t idx = 0; idx &lt; 16; ++idx) {        size_t j = 0;        for&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-486287","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/486287","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=486287"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/486287\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=486287"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=486287"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=486287"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}