| <!DOCTYPE html> |
| <html class="writer-html5" lang="en"> |
| <head> |
| <meta charset="utf-8" /> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
| <title>Efficient and performance-portable vector software — HIGHWAY nightly documentation</title> |
| <link rel="stylesheet" type="text/css" href="_static/pygments.css" /> |
| <link rel="stylesheet" type="text/css" href="_static/css/theme.css" /> |
| <link rel="stylesheet" type="text/css" href="_static/css/toggle.css" /> |
| |
| |
| <link rel="shortcut icon" href="_static/logo-32x32.ico"/> |
| <!--[if lt IE 9]> |
| <script src="_static/js/html5shiv.min.js"></script> |
| <![endif]--> |
| |
| <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> |
| <script src="_static/jquery.js"></script> |
| <script src="_static/underscore.js"></script> |
| <script src="_static/_sphinx_javascript_frameworks_compat.js"></script> |
| <script src="_static/doctools.js"></script> |
| <script src="_static/sphinx_highlight.js"></script> |
| <script src="_static/js/toggle.js"></script> |
| <script src="_static/js/theme.js"></script> |
| <link rel="index" title="Index" href="genindex.html" /> |
| <link rel="search" title="Search" href="search.html" /> |
| <link rel="next" title="API synopsis / quick reference" href="quick_reference.html" /> |
| <link rel="prev" title="Highway, a C++ library that provides portable SIMD/vector intrinsics" href="index.html" /> |
| </head> |
| |
| <body class="wy-body-for-nav"> |
| <div class="wy-grid-for-nav"> |
| <nav data-toggle="wy-nav-shift" class="wy-nav-side"> |
| <div class="wy-side-scroll"> |
| <div class="wy-side-nav-search" > |
| |
| |
| |
| <a href="index.html" class="icon icon-home"> |
| HIGHWAY |
| <img src="_static/logo.png" class="logo" alt="Logo"/> |
| </a> |
| <div class="version"> |
| test_904484786 |
| </div> |
| <div role="search"> |
| <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> |
| <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> |
| <input type="hidden" name="check_keywords" value="yes" /> |
| <input type="hidden" name="area" value="default" /> |
| </form> |
| </div> |
| </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> |
| <p class="caption" role="heading"><span class="caption-text">Contents:</span></p> |
| <ul class="current"> |
| <li class="toctree-l1 current"><a class="current reference internal" href="#">Efficient and performance-portable vector software</a><ul> |
| <li class="toctree-l2"><a class="reference internal" href="#why">Why</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="#how">How</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="#examples">Examples</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="#current-status">Current status</a><ul> |
| <li class="toctree-l3"><a class="reference internal" href="#targets">Targets</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#versioning">Versioning</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#testing">Testing</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#related-modules">Related modules</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#other-libraries">Other libraries</a></li> |
| </ul> |
| </li> |
| <li class="toctree-l2"><a class="reference internal" href="#installation">Installation</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="#building-highway-using-vcpkg">Building highway - Using vcpkg</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="#quick-start">Quick start</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="#compiler-flags">Compiler flags</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="#strip-mining-loops">Strip-mining loops</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="#additional-resources">Additional resources</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="#acknowledgments">Acknowledgments</a></li> |
| </ul> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="quick_reference.html">API synopsis / quick reference</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="design_philosophy.html">Design philosophy</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="faq.html">Frequently Asked Questions</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="impl_details.html">Highway implementation details</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="release_testing_process.html">Release testing process</a></li> |
| </ul> |
| |
| </div> |
| </div> |
| </nav> |
| |
| <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > |
| <i data-toggle="wy-nav-top" class="fa fa-bars"></i> |
| <a href="index.html">HIGHWAY</a> |
| </nav> |
| |
| <div class="wy-nav-content"> |
| <div class="rst-content"> |
| <div role="navigation" aria-label="Page navigation"> |
| <ul class="wy-breadcrumbs"> |
| <li><a href="index.html" class="icon icon-home" aria-label="Home"></a></li> |
| <li class="breadcrumb-item active">Efficient and performance-portable vector software</li> |
| <li class="wy-breadcrumbs-aside"> |
| <a href="https://github.com/google/highway/blob/master/docs/README.rst" class="fa fa-github"> Edit on GitHub</a> |
| </li> |
| </ul> |
| <hr/> |
| </div> |
| <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> |
| <div itemprop="articleBody"> |
| |
| <div class="section" id="efficient-and-performance-portable-vector-software"> |
| <h1>Efficient and performance-portable vector software<a class="headerlink" href="#efficient-and-performance-portable-vector-software" title="Permalink to this heading"></a></h1> |
| <p>Highway is a C++ library that provides portable SIMD/vector intrinsics.</p> |
| <p><a class="reference external" href="https://google.github.io/highway/en/master/">Documentation</a></p> |
| <p>Previously licensed under Apache 2, now dual-licensed as Apache 2 / |
| BSD-3.</p> |
| <div class="section" id="why"> |
| <h2>Why<a class="headerlink" href="#why" title="Permalink to this heading"></a></h2> |
| <p>We are passionate about high-performance software. We see major untapped |
| potential in CPUs (servers, mobile, desktops). Highway is for engineers |
| who want to reliably and economically push the boundaries of what is |
| possible in software.</p> |
| </div> |
| <div class="section" id="how"> |
| <h2>How<a class="headerlink" href="#how" title="Permalink to this heading"></a></h2> |
| <p>CPUs provide SIMD/vector instructions that apply the same operation to |
| multiple data items. This can reduce energy usage e.g. <em>fivefold</em> |
| because fewer instructions are executed. We also often see <em>5-10x</em> |
| speedups.</p> |
| <p>Highway makes SIMD/vector programming practical and workable according |
| to these guiding principles:</p> |
| <p><strong>Does what you expect</strong>: Highway is a C++ library with carefully-chosen |
| functions that map well to CPU instructions without extensive compiler |
| transformations. The resulting code is more predictable and robust to |
| code changes/compiler updates than autovectorization.</p> |
| <p><strong>Works on widely-used platforms</strong>: Highway supports seven |
| architectures; the same application code can target various instruction |
| sets, including those with ‘scalable’ vectors (size unknown at compile |
| time). Highway only requires C++17 (language features, not necessarily |
| the library) and supports four families of compilers. If you want to use |
| Highway on other platforms, please raise an issue.</p> |
| <p><strong>Flexible to deploy</strong>: Applications using Highway can run on |
| heterogeneous clouds or client devices, choosing the best available |
| instruction set at runtime. Alternatively, developers may choose to |
| target a single instruction set without any runtime overhead. In both |
| cases, the application code is the same except for swapping |
| <code class="docutils literal notranslate"><span class="pre">HWY_STATIC_DISPATCH</span></code> with <code class="docutils literal notranslate"><span class="pre">HWY_DYNAMIC_DISPATCH</span></code> plus one line of |
| code. See also @kfjahnke’s <a class="reference external" href="https://github.com/kfjahnke/zimt/blob/main/examples/multi_isa_example/multi_simd_isa.md">introduction to |
| dispatching</a>.</p> |
| <p><strong>Suitable for a variety of domains</strong>: Highway provides an extensive set |
| of operations, used for image processing (floating-point), compression, |
| video analysis, linear algebra, cryptography, sorting and random |
| generation. We recognise that new use-cases may require additional ops |
| and are happy to add them where it makes sense (e.g. no performance |
| cliffs on some architectures). If you would like to discuss, please file |
| an issue.</p> |
| <p><strong>Rewards data-parallel design</strong>: Highway provides tools such as Gather, |
| MaskedLoad, and FixedTag to enable speedups for legacy data structures. |
| However, the biggest gains are unlocked by designing algorithms and data |
| structures for scalable vectors. Helpful techniques include batching, |
| structure-of-array layouts, and aligned/padded allocations.</p> |
| <p>We recommend these resources for getting started:</p> |
| <ul class="simple"> |
| <li><p><a class="reference external" href="https://www.youtube.com/watch?v=R57biOOhnJM">SIMD programming with Highway |
| talk</a></p></li> |
| <li><p><a class="reference external" href="http://const.me/articles/simd/simd.pdf">SIMD for C++ Developers</a></p></li> |
| <li><p><a class="reference external" href="https://en.algorithmica.org/hpc/">Algorithms for Modern Hardware</a></p></li> |
| <li><p><a class="reference external" href="https://agner.org/optimize/optimizing_cpp.pdf">Optimizing software in |
| C++</a></p></li> |
| <li><p><a class="reference external" href="https://stackoverflow.blog/2020/07/08/improving-performance-with-simd-intrinsics-in-three-use-cases/">Improving performance with SIMD intrinsics in three use |
| cases</a></p></li> |
| </ul> |
| </div> |
| <div class="section" id="examples"> |
| <h2>Examples<a class="headerlink" href="#examples" title="Permalink to this heading"></a></h2> |
| <p>Online demos using Compiler Explorer:</p> |
| <ul class="simple"> |
| <li><p><a class="reference external" href="https://gcc.godbolt.org/z/KM3ben7ET">multiple targets with dynamic |
| dispatch</a> (more complicated, |
| but flexible and uses best available SIMD)</p></li> |
| <li><p><a class="reference external" href="https://gcc.godbolt.org/z/rGnjMevKG">single target using -m |
| flags</a> (simpler, but |
| requires/only uses the instruction set enabled by compiler flags)</p></li> |
| </ul> |
| <p>We have prepared several tutorial-like examples in hwy/examples; see the |
| README.md there for more information.</p> |
| <p>Basics:</p> |
| <ul class="simple"> |
| <li><p>sum_array_advanced.cc: 4x unrolling and remainder handling.</p></li> |
| <li><p>dot_product_unroll.cc: similar to sum_array_advanced, plus reduction.</p></li> |
| <li><p>matrix_transpose_scatter_gather: shows/compares Scatter and Gather.</p></li> |
| </ul> |
| <p>Infrastructure:</p> |
| <ul class="simple"> |
| <li><p>benchmark.cc: dot product with remainder-free loops and benchmarking.</p></li> |
| <li><p>profiler_example: shows how to use the our built-in profiler for |
| measuring the time cost of annotated zones.</p></li> |
| <li><p>skeleton*: a complete example of a module with runtime dispatch.</p></li> |
| </ul> |
| <p>Challenges:</p> |
| <ul class="simple"> |
| <li><p>masks_and_logic.cc: visualizes masks/comparisons with ASCII art.</p></li> |
| <li><p>ctf_aes.cc: capture the flag, brute-force AES password guessing.</p></li> |
| </ul> |
| <p>We observe that Highway is referenced in the following open source |
| projects, found via sourcegraph.com. Most are GitHub repositories. If |
| you would like to add your project or link to it directly, feel free to |
| raise an issue or contact us via the below email.</p> |
| <ul class="simple"> |
| <li><p>Audio: <a class="reference external" href="https://github.com/google/zimtohrli">Zimtohrli perceptual |
| metric</a></p></li> |
| <li><p>Browsers: Chromium (+Vivaldi), Firefox (+floorp / foxhound / |
| librewolf / Waterfox)</p></li> |
| <li><p>Computational biology: <a class="reference external" href="https://github.com/bnprks/BPCells">RNA |
| analysis</a>, <a class="reference external" href="https://github.com/OpenGene/fastplong">long-sequence |
| preprocessing</a></p></li> |
| <li><p>Computer graphics: ghostty-org/ghostty, <a class="reference external" href="https://github.com/rools/voxl">Sparse voxel |
| renderer</a>, <a class="reference external" href="https://github.com/Tencent/tgfx">tgfx 2D Graphics |
| library</a></p></li> |
| <li><p>Cryptography: google/distributed_point_functions, |
| google/shell-encryption</p></li> |
| <li><p>Data structures: bkille/BitLib</p></li> |
| <li><p>Image codecs: eustas/2im, <a class="reference external" href="https://github.com/GrokImageCompression/grok">Grok JPEG |
| 2000</a>, <a class="reference external" href="https://github.com/libjxl/libjxl">JPEG |
| XL</a>, |
| <a class="reference external" href="https://github.com/osamu620/JPEGenc">JPEGenc</a>, |
| <a class="reference external" href="https://github.com/google/jpegli">Jpegli</a>, |
| <a class="reference external" href="https://aomedia.googlesource.com/aom/">libaom</a>, |
| <a class="reference external" href="https://github.com/osamu620/OpenHTJ2K">OpenHTJ2K</a></p></li> |
| <li><p>Image processing: awxkee/aire, cloudinary/ssimulacra2, |
| <a class="reference external" href="https://github.com/libvips/libvips">libvips</a>, |
| m-ab-s/media-autobuild_suite,</p></li> |
| <li><p>Image viewers: AlienCowEatCake/ImageViewer, diffractor/diffractor, |
| <a class="reference external" href="https://bitbucket.org/kfj/pv/">Lux panorama/image viewer</a>, |
| mirillis/jpegxl-wic</p></li> |
| <li><p>Information retrieval: <a class="reference external" href="https://github.com/iresearch-toolkit/iresearch">iresearch database |
| index</a>, |
| michaeljclark/zvec, <a class="reference external" href="https://github.com/varchar-io/nebula">nebula interactive analytics / |
| OLAP</a>, <code class="docutils literal notranslate"><span class="pre">`ScaNN</span></code> Scalable |
| Nearest |
| Neighbors <<a class="reference external" href="https://github.com/google-research/google-research/tree/7a269cb2ce0ae1db591fe11b62cbc0be7d72532a/scann">https://github.com/google-research/google-research/tree/7a269cb2ce0ae1db591fe11b62cbc0be7d72532a/scann</a>>`__,</p></li> |
| <li><p>Machine learning: array2d/deepx, |
| <a class="reference external" href="https://github.com/google/gemma.cpp">gemma.cpp</a>, Tensorflow, |
| Numpy, zpye/SimpleInfer</p></li> |
| <li><p>Programming languages: <a class="reference external" href="https://github.com/exaloop/codon">AOT-compiled |
| python</a>, oven-sh/bun, V8/V8, |
| yinqiwen/rapidudf</p></li> |
| <li><p>Robotics: <a class="reference external" href="https://github.com/RobotLocomotion/drake">MIT Model-Based Design and |
| Verification</a></p></li> |
| <li><p>Vector search: 1yefuwang1/vectorlite, vespa-engine/vespa</p></li> |
| </ul> |
| <p>Other</p> |
| <ul class="simple"> |
| <li><p><a class="reference external" href="https://www.mnm-team.org/pub/Fopras/rock23/">Evaluation of C++ SIMD |
| Libraries</a>: “Highway |
| excelled with a strong performance across multiple SIMD extensions |
| [..]. Thus, Highway may currently be the most suitable SIMD library |
| for many software projects.”</p></li> |
| <li><p><a class="reference external" href="https://github.com/kfjahnke/zimt">zimt</a>: C++11 template library |
| to process n-dimensional arrays with multi-threaded SIMD code</p></li> |
| <li><p><a class="reference external" href="https://github.com/google/highway/tree/master/hwy/contrib/sort">vectorized |
| Quicksort</a> |
| (<a class="reference external" href="https://arxiv.org/abs/2205.05982">paper</a>)</p></li> |
| </ul> |
| <p>Highway can also be installed via a package manager or from a |
| repository:</p> |
| <details><summary><p>Click to expand BSD repositories</p> |
| </summary><ul class="simple"> |
| <li><p><a class="reference external" href="https://github.com/DragonFlyBSD/DPorts/tree/master/devel/highway">DragonFlyBSD</a></p></li> |
| <li><p><a class="reference external" href="https://cgit.freebsd.org/ports/tree/devel/highway">FreeBSD</a></p></li> |
| <li><p><a class="reference external" href="https://github.com/ghostbsd/ghostbsd-ports/tree/main/devel/highway">GhostBSD</a></p></li> |
| <li><p><a class="reference external" href="https://www.midnightbsd.org/mports/devel/highway/README.html">MidnightBSD</a></p></li> |
| </ul> |
| </details><details><summary><p>Click to expand cross platform package repositories</p> |
| </summary><ul class="simple"> |
| <li><p><a class="reference external" href="https://conan.io/center/recipes/highway">conan-io</a></p></li> |
| <li><p><a class="reference external" href="https://anaconda.org/channels/conda-forge/packages/libhwy/overview">conda-forge</a></p></li> |
| <li><p><a class="reference external" href="https://docs.easybuild.io/version-specific/supported-software/h/Highway/">EasyBuild</a></p></li> |
| <li><p><a class="reference external" href="https://formulae.brew.sh/formula/highway">Homebrew</a></p></li> |
| <li><p><a class="reference external" href="https://vcpkg.io/en/package/highway">microsoft/vcpkg</a></p></li> |
| <li><p><a class="reference external" href="https://packages.spack.io/package.html?name=highway">spack</a></p></li> |
| <li><p><a class="reference external" href="https://github.com/xmake-io/xmake-repo/tree/dev/packages/h/highway">xmake-io/xmake-repo</a></p></li> |
| </ul> |
| </details><details><summary><p>Click to expand linux package repositories</p> |
| </summary><p>Obtained from |
| <a class="reference external" href="https://repology.org/project/highway-simd-library/versions">repology</a></p> |
| <p><a class="reference external" href="https://repology.org/project/highway-simd-library/versions"><img alt="Packaging status" src="https://repology.org/badge/vertical-allrepos/highway-simd-library.svg" /></a></p> |
| </details><details><summary><p>Click to expand Windows package repositories</p> |
| </summary><ul class="simple"> |
| <li><p><a class="reference external" href="https://github.com/fd00/yacp/tree/master/highway">fd00/yacp</a></p></li> |
| <li><p><a class="reference external" href="https://packages.msys2.org/search?t=binpkg&q=highway">MSYS2</a></p></li> |
| </ul> |
| </details><details><summary><p>Click to expand other operating systems and environments where Highway |
| has been used</p> |
| </summary><ul class="simple"> |
| <li><p><a class="reference external" href="https://opnsense.org/">OPNsense</a></p></li> |
| <li><p><a class="reference external" href="https://github.com/Xilinx/Vitis_Libraries">Xilinx/Vitis_Libraries</a></p></li> |
| </ul> |
| </details></div> |
| <div class="section" id="current-status"> |
| <h2>Current status<a class="headerlink" href="#current-status" title="Permalink to this heading"></a></h2> |
| <div class="section" id="targets"> |
| <h3>Targets<a class="headerlink" href="#targets" title="Permalink to this heading"></a></h3> |
| <p>Highway supports 27 targets, listed in alphabetical order of platform:</p> |
| <ul class="simple"> |
| <li><p>Any: <code class="docutils literal notranslate"><span class="pre">EMU128</span></code>, <code class="docutils literal notranslate"><span class="pre">SCALAR</span></code>;</p></li> |
| <li><p>Armv7+: <code class="docutils literal notranslate"><span class="pre">NEON_WITHOUT_AES</span></code>, <code class="docutils literal notranslate"><span class="pre">NEON</span></code>, <code class="docutils literal notranslate"><span class="pre">NEON_BF16</span></code>, <code class="docutils literal notranslate"><span class="pre">SVE</span></code>, |
| <code class="docutils literal notranslate"><span class="pre">SVE2</span></code>, <code class="docutils literal notranslate"><span class="pre">SVE_256</span></code>, <code class="docutils literal notranslate"><span class="pre">SVE2_128</span></code>;</p></li> |
| <li><p>IBM Z: <code class="docutils literal notranslate"><span class="pre">Z14</span></code>, <code class="docutils literal notranslate"><span class="pre">Z15</span></code>;</p></li> |
| <li><p>LoongArch: <code class="docutils literal notranslate"><span class="pre">LSX</span></code>, <code class="docutils literal notranslate"><span class="pre">LASX</span></code>;</p></li> |
| <li><p>POWER: <code class="docutils literal notranslate"><span class="pre">PPC8</span></code> (v2.07), <code class="docutils literal notranslate"><span class="pre">PPC9</span></code> (v3.0), <code class="docutils literal notranslate"><span class="pre">PPC10</span></code> (v3.1B, not yet |
| supported due to compiler bugs, see #1207; also requires QEMU 7.2);</p></li> |
| <li><p>RISC-V: <code class="docutils literal notranslate"><span class="pre">RVV</span></code> (1.0);</p></li> |
| <li><p>WebAssembly: <code class="docutils literal notranslate"><span class="pre">WASM</span></code>, <code class="docutils literal notranslate"><span class="pre">WASM_EMU256</span></code> (a 2x unrolled version of |
| wasm128, enabled if <code class="docutils literal notranslate"><span class="pre">HWY_WANT_WASM2</span></code> is defined. This will remain |
| supported until it is potentially superseded by a future version of |
| WASM.);</p></li> |
| <li><p>x86:</p> |
| <ul> |
| <li><p><code class="docutils literal notranslate"><span class="pre">SSE2</span></code></p></li> |
| <li><p><code class="docutils literal notranslate"><span class="pre">SSSE3</span></code> (~Intel Core)</p></li> |
| <li><p><code class="docutils literal notranslate"><span class="pre">SSE4</span></code> (~Nehalem, also includes AES + CLMUL).</p></li> |
| <li><p><code class="docutils literal notranslate"><span class="pre">AVX2</span></code> (~Haswell, also includes BMI2 + F16 + FMA)</p></li> |
| <li><p><code class="docutils literal notranslate"><span class="pre">AVX3</span></code> (~Skylake, AVX-512F/BW/CD/DQ/VL)</p></li> |
| <li><p><code class="docutils literal notranslate"><span class="pre">AVX3_DL</span></code> (~Icelake, includes <code class="docutils literal notranslate"><span class="pre">BitAlg</span></code> + <code class="docutils literal notranslate"><span class="pre">CLMUL</span></code> + <code class="docutils literal notranslate"><span class="pre">GFNI</span></code> |
| + <code class="docutils literal notranslate"><span class="pre">AVX512IFMA</span></code> + <code class="docutils literal notranslate"><span class="pre">VAES</span></code> + <code class="docutils literal notranslate"><span class="pre">VBMI</span></code> + <code class="docutils literal notranslate"><span class="pre">VBMI2</span></code> + |
| <code class="docutils literal notranslate"><span class="pre">AVX512VNNI</span></code> + <code class="docutils literal notranslate"><span class="pre">VPOPCNT</span></code>),</p></li> |
| <li><p><code class="docutils literal notranslate"><span class="pre">AVX3_ZEN4</span></code> (AVX3_DL plus BF16, optimized for AMD Zen4; requires |
| opt-in by defining <code class="docutils literal notranslate"><span class="pre">HWY_WANT_AVX3_ZEN4</span></code> if compiling for static |
| dispatch, but enabled by default for runtime dispatch),</p></li> |
| <li><p><code class="docutils literal notranslate"><span class="pre">AVX3_SPR</span></code> (~Sapphire Rapids, includes AVX-512FP16 + AMX-TILE + |
| AMX-BF16 + AMX-INT8)</p></li> |
| <li><p><code class="docutils literal notranslate"><span class="pre">AVX10_2</span></code> (~Diamond Rapids)</p></li> |
| </ul> |
| </li> |
| </ul> |
| <p>Our policy is that unless otherwise specified, targets will remain |
| supported as long as they can be (cross-)compiled with currently |
| supported Clang or GCC, and tested using QEMU. If the target can be |
| compiled with LLVM trunk and tested using our version of QEMU without |
| extra flags, then it is eligible for inclusion in our continuous testing |
| infrastructure. Otherwise, the target will be manually tested before |
| releases with selected versions/configurations of Clang and GCC.</p> |
| <p>SVE was initially tested using farm_sve (see acknowledgments).</p> |
| </div> |
| <div class="section" id="versioning"> |
| <h3>Versioning<a class="headerlink" href="#versioning" title="Permalink to this heading"></a></h3> |
| <p>Highway releases aim to follow the semver.org system |
| (MAJOR.MINOR.PATCH), incrementing MINOR after backward-compatible |
| additions and PATCH after backward-compatible fixes. We recommend using |
| releases (rather than the Git tip) because they are tested more |
| extensively, see below.</p> |
| <p>The current version 1.0 signals an increased focus on backwards |
| compatibility. Applications using documented functionality will remain |
| compatible with future updates that have the same major version number.</p> |
| </div> |
| <div class="section" id="testing"> |
| <h3>Testing<a class="headerlink" href="#testing" title="Permalink to this heading"></a></h3> |
| <p>Continuous integration tests build with a recent version of Clang |
| (running on native x86, or QEMU for RISC-V and Arm) and MSVC 2019 |
| (v19.28, running on native x86).</p> |
| <p>Before releases, we also test on x86 with Clang and GCC, and Armv7/8 via |
| GCC cross-compile. See release_testing_process.md for details.</p> |
| </div> |
| <div class="section" id="related-modules"> |
| <h3>Related modules<a class="headerlink" href="#related-modules" title="Permalink to this heading"></a></h3> |
| <p>The <code class="docutils literal notranslate"><span class="pre">contrib</span></code> directory contains SIMD-related utilities: an image |
| class with aligned rows, a math library (16 functions already |
| implemented, mostly trigonometry), and functions for computing dot |
| products and sorting.</p> |
| </div> |
| <div class="section" id="other-libraries"> |
| <h3>Other libraries<a class="headerlink" href="#other-libraries" title="Permalink to this heading"></a></h3> |
| <p>If you only require x86 support, you may also use Agner Fog’s <a class="reference external" href="https://github.com/vectorclass">VCL |
| vector class library</a>. It includes |
| many functions including a complete math library.</p> |
| <p>If you have existing code using x86/NEON intrinsics, you may be |
| interested in <a class="reference external" href="https://github.com/simd-everywhere/simde">SIMDe</a>, |
| which emulates those intrinsics using other platforms’ intrinsics or |
| autovectorization.</p> |
| <p><a class="reference external" href="https://github.com/xtensor-stack/xsimd">xSIMD</a> is a header only C++ |
| library. It supports Arm, Power, RISC-V, WebAssembly and x86 targets. |
| Has a high level interface, but fewer supported operations.</p> |
| <p><a class="reference external" href="https://github.com/ashvardanian/NumKong">NumKong</a> a SIMD accelerated |
| math C library focused on operations such as dot products and mixed |
| precision matrix multiplications. It can be used from C++, Go, Python, |
| Rust, Swift and WebAssembly. Accelerated operations are available on |
| Arm, LoongArch, Power, RISC-V and x86.</p> |
| </div> |
| </div> |
| <div class="section" id="installation"> |
| <h2>Installation<a class="headerlink" href="#installation" title="Permalink to this heading"></a></h2> |
| <p>This project uses CMake to generate and build. In a Debian-based system |
| you can install it via:</p> |
| <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>sudo<span class="w"> </span>apt<span class="w"> </span>install<span class="w"> </span>cmake |
| </pre></div> |
| </div> |
| <p>Highway’s unit tests use |
| <a class="reference external" href="https://github.com/google/googletest">googletest</a>. By default, |
| Highway’s CMake downloads this dependency at configuration time. You can |
| avoid this by setting the <code class="docutils literal notranslate"><span class="pre">HWY_SYSTEM_GTEST</span></code> CMake variable to ON and |
| installing gtest separately:</p> |
| <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>sudo<span class="w"> </span>apt<span class="w"> </span>install<span class="w"> </span>libgtest-dev |
| </pre></div> |
| </div> |
| <p>Alternatively, you can define <code class="docutils literal notranslate"><span class="pre">HWY_TEST_STANDALONE=1</span></code> and remove all |
| occurrences of <code class="docutils literal notranslate"><span class="pre">gtest_main</span></code> in each BUILD file, then tests avoid the |
| dependency on GUnit.</p> |
| <p>Running cross-compiled tests requires support from the OS, which on |
| Debian is provided by the <code class="docutils literal notranslate"><span class="pre">qemu-user-binfmt</span></code> package.</p> |
| <p>To build Highway as a shared or static library (depending on |
| BUILD_SHARED_LIBS), the standard CMake workflow can be used:</p> |
| <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>mkdir<span class="w"> </span>-p<span class="w"> </span>build<span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="nb">cd</span><span class="w"> </span>build |
| cmake<span class="w"> </span>.. |
| make<span class="w"> </span>-j<span class="w"> </span><span class="o">&&</span><span class="w"> </span>make<span class="w"> </span><span class="nb">test</span> |
| </pre></div> |
| </div> |
| <p>Or you can run <code class="docutils literal notranslate"><span class="pre">run_tests.sh</span></code> (<code class="docutils literal notranslate"><span class="pre">run_tests.bat</span></code> on Windows).</p> |
| <p>Bazel is also supported for building, but it is not as widely |
| used/tested.</p> |
| <p>When building for Armv7, a limitation of current compilers requires you |
| to add <code class="docutils literal notranslate"><span class="pre">-DHWY_CMAKE_ARM7:BOOL=ON</span></code> to the CMake command line; see #834 |
| and #1032. We understand that work is underway to remove this |
| limitation.</p> |
| <p>To benefit from Armv8/v9 vusdot and vusdotq instructions, you can add |
| “+i8mm” to the -march compiler flag, assuming the target CPU(s) support |
| that.</p> |
| <p>Building on 32-bit x86 is not officially supported, and AVX2/3 are |
| disabled by default there. Note that johnplatts has successfully built |
| and run the Highway tests on 32-bit x86, including AVX2/3, on GCC 7/8 |
| and Clang 8/11/12. On Ubuntu 22.04, Clang 11 and 12, but not later |
| versions, require extra compiler flags |
| <code class="docutils literal notranslate"><span class="pre">-m32</span> <span class="pre">-isystem</span> <span class="pre">/usr/i686-linux-gnu/include</span></code>. Clang 10 and earlier |
| require the above plus |
| <code class="docutils literal notranslate"><span class="pre">-isystem</span> <span class="pre">/usr/i686-linux-gnu/include/c++/12/i686-linux-gnu</span></code>. See |
| <a class="reference external" href="https://github.com/google/highway/issues/1279">#1279</a>.</p> |
| </div> |
| <div class="section" id="building-highway-using-vcpkg"> |
| <h2>Building highway - Using vcpkg<a class="headerlink" href="#building-highway-using-vcpkg" title="Permalink to this heading"></a></h2> |
| <p>highway is now available in |
| <a class="reference external" href="https://github.com/Microsoft/vcpkg">vcpkg</a></p> |
| <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>vcpkg<span class="w"> </span>install<span class="w"> </span>highway |
| </pre></div> |
| </div> |
| <p>The highway port in vcpkg is kept up to date by Microsoft team members |
| and community contributors. If the version is out of date, please |
| <a class="reference external" href="https://github.com/Microsoft/vcpkg">create an issue or pull request</a> |
| on the vcpkg repository.</p> |
| </div> |
| <div class="section" id="quick-start"> |
| <h2>Quick start<a class="headerlink" href="#quick-start" title="Permalink to this heading"></a></h2> |
| <p>You can use the <code class="docutils literal notranslate"><span class="pre">benchmark</span></code> inside examples/ as a starting point.</p> |
| <p>quick_reference.md briefly lists all operations and their parameters, |
| and instruction_matrix.md indicates the number of instructions per |
| operation.</p> |
| <p>faq.md answers questions about portability, API design and where to find |
| more information.</p> |
| <p>We recommend using full SIMD vectors whenever possible for maximum |
| performance portability. To obtain them, pass a <code class="docutils literal notranslate"><span class="pre">ScalableTag<float></span></code> |
| (or equivalently <code class="docutils literal notranslate"><span class="pre">HWY_FULL(float)</span></code>) tag to functions such as |
| <code class="docutils literal notranslate"><span class="pre">Zero/Set/Load</span></code>. There are two alternatives for use-cases requiring an |
| upper bound on the lanes:</p> |
| <ul class="simple"> |
| <li><p>For up to <code class="docutils literal notranslate"><span class="pre">N</span></code> lanes, specify <code class="docutils literal notranslate"><span class="pre">CappedTag<T,</span> <span class="pre">N></span></code> or the equivalent |
| <code class="docutils literal notranslate"><span class="pre">HWY_CAPPED(T,</span> <span class="pre">N)</span></code>. The actual number of lanes will be <code class="docutils literal notranslate"><span class="pre">N</span></code> |
| rounded down to the nearest power of two, such as 4 if <code class="docutils literal notranslate"><span class="pre">N</span></code> is 5, or |
| 8 if <code class="docutils literal notranslate"><span class="pre">N</span></code> is 8. This is useful for data structures such as a narrow |
| matrix. A loop is still required because vectors may actually have |
| fewer than <code class="docutils literal notranslate"><span class="pre">N</span></code> lanes.</p></li> |
| <li><p>For exactly a power of two <code class="docutils literal notranslate"><span class="pre">N</span></code> lanes, specify <code class="docutils literal notranslate"><span class="pre">FixedTag<T,</span> <span class="pre">N></span></code>. |
| The largest supported <code class="docutils literal notranslate"><span class="pre">N</span></code> depends on the target, but is guaranteed |
| to be at least <code class="docutils literal notranslate"><span class="pre">16/sizeof(T)</span></code>.</p></li> |
| </ul> |
| <p>Due to ADL restrictions, user code calling Highway ops must either:</p> |
| <ul class="simple"> |
| <li><p>Reside inside <code class="docutils literal notranslate"><span class="pre">namespace</span> <span class="pre">hwy</span> <span class="pre">{</span> <span class="pre">namespace</span> <span class="pre">HWY_NAMESPACE</span> <span class="pre">{</span></code>; or</p></li> |
| <li><p>prefix each op with an alias such as |
| <code class="docutils literal notranslate"><span class="pre">namespace</span> <span class="pre">hn</span> <span class="pre">=</span> <span class="pre">hwy::HWY_NAMESPACE;</span>     <span class="pre">hn::Add()</span></code>; or</p></li> |
| <li><p>add using-declarations for each op used: |
| <code class="docutils literal notranslate"><span class="pre">using</span> <span class="pre">hwy::HWY_NAMESPACE::Add;</span></code>.</p></li> |
| </ul> |
| <p>Additionally, each function that calls Highway ops (such as <code class="docutils literal notranslate"><span class="pre">Load</span></code>) |
| must either be prefixed with <code class="docutils literal notranslate"><span class="pre">HWY_ATTR</span></code>, OR reside between |
| <code class="docutils literal notranslate"><span class="pre">HWY_BEFORE_NAMESPACE()</span></code> and <code class="docutils literal notranslate"><span class="pre">HWY_AFTER_NAMESPACE()</span></code>. Lambda |
| functions currently require <code class="docutils literal notranslate"><span class="pre">HWY_ATTR</span></code> before their opening brace.</p> |
| <p>Do not use namespace-scope nor <code class="docutils literal notranslate"><span class="pre">static</span></code> initializers for SIMD vectors |
| because this can cause SIGILL when using runtime dispatch and the |
| compiler chooses an initializer compiled for a target not supported by |
| the current CPU. Instead, constants initialized via <code class="docutils literal notranslate"><span class="pre">Set</span></code> should |
| generally be local (const) variables.</p> |
| <p>The entry points into code using Highway differ slightly depending on |
| whether they use static or dynamic dispatch. In both cases, we recommend |
| that the top-level function receives one or more pointers to arrays, |
| rather than target-specific vector types.</p> |
| <ul class="simple"> |
| <li><p>For static dispatch, <code class="docutils literal notranslate"><span class="pre">HWY_TARGET</span></code> will be the best available target |
| among <code class="docutils literal notranslate"><span class="pre">HWY_BASELINE_TARGETS</span></code>, i.e. those allowed for use by the |
| compiler (see quick_reference.md). Functions inside <code class="docutils literal notranslate"><span class="pre">HWY_NAMESPACE</span></code> |
| can be called using <code class="docutils literal notranslate"><span class="pre">HWY_STATIC_DISPATCH(func)(args)</span></code> within the |
| same module they are defined in. You can call the function from other |
| modules by wrapping it in a regular function and declaring the |
| regular function in a header.</p></li> |
| <li><p>For dynamic dispatch, a table of function pointers is generated via |
| the <code class="docutils literal notranslate"><span class="pre">HWY_EXPORT</span></code> macro that is used by |
| <code class="docutils literal notranslate"><span class="pre">HWY_DYNAMIC_DISPATCH(func)(args)</span></code> to call the best function |
| pointer for the current CPU’s supported targets. A module is |
| automatically compiled for each target in <code class="docutils literal notranslate"><span class="pre">HWY_TARGETS</span></code> (see |
| quick_reference.md) if <code class="docutils literal notranslate"><span class="pre">HWY_TARGET_INCLUDE</span></code> is defined and |
| <code class="docutils literal notranslate"><span class="pre">foreach_target.h</span></code> is included. Note that the first invocation of |
| <code class="docutils literal notranslate"><span class="pre">HWY_DYNAMIC_DISPATCH</span></code>, or each call to the pointer returned by the |
| first invocation of <code class="docutils literal notranslate"><span class="pre">HWY_DYNAMIC_POINTER</span></code>, involves some CPU |
| detection overhead. You can prevent this by calling the following |
| before any invocation of <code class="docutils literal notranslate"><span class="pre">HWY_DYNAMIC_*</span></code>: |
| <code class="docutils literal notranslate"><span class="pre">hwy::GetChosenTarget().Update(hwy::SupportedTargets());</span></code>.</p></li> |
| </ul> |
| <p>See also a separate <a class="reference external" href="https://github.com/kfjahnke/zimt/blob/multi_isa/examples/multi_isa_example/multi_simd_isa.md">introduction to dynamic |
| dispatch</a> |
| by @kfjahnke.</p> |
| <p>When using dynamic dispatch, <code class="docutils literal notranslate"><span class="pre">foreach_target.h</span></code> is included from |
| translation units (.cc files), not headers. Headers containing vector |
| code shared between several translation units require a special include |
| guard, for example the following taken from <code class="docutils literal notranslate"><span class="pre">examples/skeleton-inl.h</span></code>:</p> |
| <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">#if defined(HIGHWAY_HWY_EXAMPLES_SKELETON_INL_H_) == defined(HWY_TARGET_TOGGLE)</span> |
| <span class="c1">#ifdef HIGHWAY_HWY_EXAMPLES_SKELETON_INL_H_</span> |
| <span class="c1">#undef HIGHWAY_HWY_EXAMPLES_SKELETON_INL_H_</span> |
| <span class="c1">#else</span> |
| <span class="c1">#define HIGHWAY_HWY_EXAMPLES_SKELETON_INL_H_</span> |
| <span class="c1">#endif</span> |
| |
| <span class="c1">#include "hwy/highway.h"</span> |
| <span class="o">//</span> <span class="n">Your</span> <span class="n">vector</span> <span class="n">code</span> |
| <span class="c1">#endif</span> |
| </pre></div> |
| </div> |
| <p>By convention, we name such headers <code class="docutils literal notranslate"><span class="pre">-inl.h</span></code> because their contents |
| (often function templates) are usually inlined.</p> |
| </div> |
| <div class="section" id="compiler-flags"> |
| <h2>Compiler flags<a class="headerlink" href="#compiler-flags" title="Permalink to this heading"></a></h2> |
| <p>Applications should be compiled with optimizations enabled. Without |
| inlining SIMD code may slow down by factors of 10 to 100. For clang and |
| GCC, <code class="docutils literal notranslate"><span class="pre">-O2</span></code> is generally sufficient.</p> |
| <p>For Clang and GCC, we recommend using dynamic dispatch (see Quick |
| start), because this avoids the need for extra compiler flags which may |
| be incompatible with other libraries and always uses the best available |
| instructions. If you know exactly which CPU you are running on, you can |
| specify that as the baseline target, which avoids generating code for |
| any older instruction sets. Compiler flags must match the predefined |
| macro checks for <code class="docutils literal notranslate"><span class="pre">HWY_BASELINE_*</span></code> in <code class="docutils literal notranslate"><span class="pre">detect_targets.h</span></code>. They can |
| also be deduced from the <code class="docutils literal notranslate"><span class="pre">HWY_TARGET_STR</span></code> in <code class="docutils literal notranslate"><span class="pre">set_macros-inl.h</span></code>. For |
| x86, suggested flags are currently:</p> |
| <ul class="simple"> |
| <li><p><code class="docutils literal notranslate"><span class="pre">HWY_AVX2</span></code>: <code class="docutils literal notranslate"><span class="pre">-march=x86-64-v3</span> <span class="pre">-maes</span> <span class="pre">-mpclmul</span></code>, or |
| <code class="docutils literal notranslate"><span class="pre">-march=haswell</span> <span class="pre">-maes</span></code></p></li> |
| <li><p><code class="docutils literal notranslate"><span class="pre">HWY_AVX3</span></code>: <code class="docutils literal notranslate"><span class="pre">-march=x86-64-v4</span></code>, or <code class="docutils literal notranslate"><span class="pre">-march=skx</span></code></p></li> |
| <li><p><code class="docutils literal notranslate"><span class="pre">HWY_AVX3_DL</span></code>: <code class="docutils literal notranslate"><span class="pre">-march=icelake-server</span></code></p></li> |
| <li><p><code class="docutils literal notranslate"><span class="pre">HWY_ZEN4</span></code>: <code class="docutils literal notranslate"><span class="pre">-march=znver4</span></code></p></li> |
| <li><p><code class="docutils literal notranslate"><span class="pre">HWY_AVX3_SPR</span></code>: |
| <code class="docutils literal notranslate"><span class="pre">-march=icelake-server</span> <span class="pre">-mavx512fp16</span> <span class="pre">-mavx512bf16</span> <span class="pre">-mamx-tile</span>     <span class="pre">-mamx-bf16</span> <span class="pre">-mamx-int8</span></code>, |
| or <code class="docutils literal notranslate"><span class="pre">-march=sapphirerapids</span></code></p></li> |
| <li><p><code class="docutils literal notranslate"><span class="pre">HWY_AVX10_2</span></code>: <code class="docutils literal notranslate"><span class="pre">-march=novalake</span></code> (requires GCC 16 or Clang 22)</p></li> |
| </ul> |
| <p>See also the godbolt examples above mentioning -m targets.</p> |
| <p>For MSVC, we recommend compiling with <code class="docutils literal notranslate"><span class="pre">/Gv</span></code> to allow non-inlined |
| functions to pass vector arguments in registers. If intending to use the |
| AVX2 target together with half-width vectors (e.g. for <code class="docutils literal notranslate"><span class="pre">PromoteTo</span></code>), |
| it is also important to compile with <code class="docutils literal notranslate"><span class="pre">/arch:AVX2</span></code>. This seems to be |
| the only way to reliably generate VEX-encoded SSE instructions on MSVC. |
| Sometimes MSVC generates VEX-encoded SSE instructions, if they are mixed |
| with AVX, but not always, see |
| <a class="reference external" href="https://developercommunity.visualstudio.com/t/10618264">DevCom-10618264</a>. |
| Otherwise, mixing VEX-encoded AVX2 instructions and non-VEX SSE may |
| cause severe performance degradation. Unfortunately, with <code class="docutils literal notranslate"><span class="pre">/arch:AVX2</span></code> |
| option, the resulting binary will then require AVX2. Note that no such |
| flag is needed for clang and GCC because they support target-specific |
| attributes, which we use to ensure proper VEX code generation for AVX2 |
| targets.</p> |
| </div> |
| <div class="section" id="strip-mining-loops"> |
| <h2>Strip-mining loops<a class="headerlink" href="#strip-mining-loops" title="Permalink to this heading"></a></h2> |
| <p>When vectorizing a loop, an important question is whether and how to |
| deal with a number of iterations (‘trip count’, denoted <code class="docutils literal notranslate"><span class="pre">count</span></code>) that |
| does not evenly divide the vector size <code class="docutils literal notranslate"><span class="pre">N</span> <span class="pre">=</span> <span class="pre">Lanes(d)</span></code>. For example, it |
| may be necessary to avoid writing past the end of an array.</p> |
| <p>In this section, let <code class="docutils literal notranslate"><span class="pre">T</span></code> denote the element type and |
| <code class="docutils literal notranslate"><span class="pre">d</span> <span class="pre">=</span> <span class="pre">ScalableTag<T></span></code>. Assume the loop body is given as a function |
| <code class="docutils literal notranslate"><span class="pre">template<bool</span> <span class="pre">partial,</span> <span class="pre">class</span> <span class="pre">D></span> <span class="pre">void</span> <span class="pre">LoopBody(D</span> <span class="pre">d,</span> <span class="pre">size_t</span> <span class="pre">index,</span> <span class="pre">size_t</span> <span class="pre">max_n)</span></code>.</p> |
| <p>“Strip-mining” is a technique for vectorizing a loop by transforming it |
| into an outer loop and inner loop, such that the number of iterations in |
| the inner loop matches the vector width. Then, the inner loop is |
| replaced with vector operations.</p> |
| <p>Highway offers several strategies for loop vectorization:</p> |
| <ul> |
| <li><p>Ensure all inputs/outputs are padded. Then the (outer) loop is simply</p> |
| <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">count</span><span class="p">;</span> <span class="n">i</span> <span class="o">+=</span> <span class="n">N</span><span class="p">)</span> <span class="n">LoopBody</span><span class="o"><</span><span class="n">false</span><span class="o">></span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> |
| </pre></div> |
| </div> |
| <p>Here, the template parameter and second function argument are not |
| needed.</p> |
| <p>This is the preferred option, unless <code class="docutils literal notranslate"><span class="pre">N</span></code> is in the thousands and |
| vector operations are pipelined with long latencies. This was the |
| case for supercomputers in the 90s, but nowadays ALUs are cheap and |
| we see most implementations split vectors into 1, 2 or 4 parts, so |
| there is little cost to processing entire vectors even if we do not |
| need all their lanes. Indeed this avoids the (potentially large) cost |
| of predication or partial loads/stores on older targets, and does not |
| duplicate code.</p> |
| </li> |
| <li><p>Process whole vectors and include previously processed elements in |
| the last vector:</p> |
| <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">count</span><span class="p">;</span> <span class="n">i</span> <span class="o">+=</span> <span class="n">N</span><span class="p">)</span> <span class="n">LoopBody</span><span class="o"><</span><span class="n">false</span><span class="o">></span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">HWY_MIN</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">count</span> <span class="o">-</span> <span class="n">N</span><span class="p">),</span> <span class="mi">0</span><span class="p">);</span> |
| </pre></div> |
| </div> |
| <p>This is the second preferred option provided that <code class="docutils literal notranslate"><span class="pre">count</span> <span class="pre">>=</span> <span class="pre">N</span></code> and |
| <code class="docutils literal notranslate"><span class="pre">LoopBody</span></code> is idempotent. Some elements might be processed twice, |
| but a single code path and full vectorization is usually worth it. |
| Even if <code class="docutils literal notranslate"><span class="pre">count</span> <span class="pre"><</span> <span class="pre">N</span></code>, it usually makes sense to pad inputs/outputs |
| up to <code class="docutils literal notranslate"><span class="pre">N</span></code>.</p> |
| </li> |
| <li><p>Use the <code class="docutils literal notranslate"><span class="pre">Transform*</span></code> functions in hwy/contrib/algo/transform-inl.h. |
| This takes care of the loop and remainder handling and you simply |
| define a generic lambda function (C++14) or functor which receives |
| the current vector from the input/output array, plus optionally |
| vectors from up to two extra input arrays, and returns the value to |
| write to the input/output array.</p> |
| <p>Here is an example implementing the BLAS function SAXPY |
| (<code class="docutils literal notranslate"><span class="pre">alpha</span> <span class="pre">*</span> <span class="pre">x</span> <span class="pre">+</span> <span class="pre">y</span></code>):</p> |
| <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Transform1</span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="p">[](</span><span class="n">auto</span> <span class="n">d</span><span class="p">,</span> <span class="n">const</span> <span class="n">auto</span> <span class="n">v</span><span class="p">,</span> <span class="n">const</span> <span class="n">auto</span> <span class="n">v1</span><span class="p">)</span> <span class="n">HWY_ATTR</span> <span class="p">{</span> |
| <span class="k">return</span> <span class="n">MulAdd</span><span class="p">(</span><span class="n">Set</span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">alpha</span><span class="p">),</span> <span class="n">v</span><span class="p">,</span> <span class="n">v1</span><span class="p">);</span> |
| <span class="p">});</span> |
| </pre></div> |
| </div> |
| </li> |
| <li><p>Process whole vectors as above, followed by a scalar loop:</p> |
| <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> |
| <span class="k">for</span> <span class="p">(;</span> <span class="n">i</span> <span class="o">+</span> <span class="n">N</span> <span class="o"><=</span> <span class="n">count</span><span class="p">;</span> <span class="n">i</span> <span class="o">+=</span> <span class="n">N</span><span class="p">)</span> <span class="n">LoopBody</span><span class="o"><</span><span class="n">false</span><span class="o">></span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> |
| <span class="k">for</span> <span class="p">(;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">count</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="n">LoopBody</span><span class="o"><</span><span class="n">false</span><span class="o">></span><span class="p">(</span><span class="n">CappedTag</span><span class="o"><</span><span class="n">T</span><span class="p">,</span> <span class="mi">1</span><span class="o">></span><span class="p">(),</span> <span class="n">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> |
| </pre></div> |
| </div> |
| <p>The template parameter and second function arguments are again not |
| needed.</p> |
| <p>This avoids duplicating code, and is reasonable if <code class="docutils literal notranslate"><span class="pre">count</span></code> is |
| large. If <code class="docutils literal notranslate"><span class="pre">count</span></code> is small, the second loop may be slower than the |
| next option.</p> |
| </li> |
| <li><p>Process whole vectors as above, followed by a single call to a |
| modified <code class="docutils literal notranslate"><span class="pre">LoopBody</span></code> with masking:</p> |
| <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> |
| <span class="k">for</span> <span class="p">(;</span> <span class="n">i</span> <span class="o">+</span> <span class="n">N</span> <span class="o"><=</span> <span class="n">count</span><span class="p">;</span> <span class="n">i</span> <span class="o">+=</span> <span class="n">N</span><span class="p">)</span> <span class="p">{</span> |
| <span class="n">LoopBody</span><span class="o"><</span><span class="n">false</span><span class="o">></span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> |
| <span class="p">}</span> |
| <span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="o"><</span> <span class="n">count</span><span class="p">)</span> <span class="p">{</span> |
| <span class="n">LoopBody</span><span class="o"><</span><span class="n">true</span><span class="o">></span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">count</span> <span class="o">-</span> <span class="n">i</span><span class="p">);</span> |
| <span class="p">}</span> |
| </pre></div> |
| </div> |
| <p>Now the template parameter and third function argument can be used |
| inside <code class="docutils literal notranslate"><span class="pre">LoopBody</span></code> to non-atomically ‘blend’ the first |
| <code class="docutils literal notranslate"><span class="pre">num_remaining</span></code> lanes of <code class="docutils literal notranslate"><span class="pre">v</span></code> with the previous contents of memory |
| at subsequent locations: |
| <code class="docutils literal notranslate"><span class="pre">BlendedStore(v,</span> <span class="pre">FirstN(d,</span> <span class="pre">num_remaining),</span> <span class="pre">d,</span> <span class="pre">pointer);</span></code>. |
| Similarly, <code class="docutils literal notranslate"><span class="pre">MaskedLoad(FirstN(d,</span> <span class="pre">num_remaining),</span> <span class="pre">d,</span> <span class="pre">pointer)</span></code> loads |
| the first <code class="docutils literal notranslate"><span class="pre">num_remaining</span></code> elements and returns zero in other lanes.</p> |
| <p>This is a good default when it is infeasible to ensure vectors are |
| padded, but is only safe <code class="docutils literal notranslate"><span class="pre">#if</span> <span class="pre">!HWY_MEM_OPS_MIGHT_FAULT</span></code>! In |
| contrast to the scalar loop, only a single final iteration is needed. |
| The increased code size from two loop bodies is expected to be |
| worthwhile because it avoids the cost of masking in all but the final |
| iteration.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="section" id="additional-resources"> |
| <h2>Additional resources<a class="headerlink" href="#additional-resources" title="Permalink to this heading"></a></h2> |
| <ul class="simple"> |
| <li><p>Highway introduction (slides): highway_intro.pdf</p></li> |
| <li><p>Overview of instructions per operation on different architectures: |
| instruction_matrix.md</p></li> |
| <li><p>Design philosophy and comparison: design_philosophy.md</p></li> |
| <li><p>Implementation details: impl_details.md</p></li> |
| </ul> |
| </div> |
| <div class="section" id="acknowledgments"> |
| <h2>Acknowledgments<a class="headerlink" href="#acknowledgments" title="Permalink to this heading"></a></h2> |
| <p>We have used <a class="reference external" href="https://gitlab.inria.fr/bramas/farm-sve">farm-sve</a> by |
| Berenger Bramas; it has proved useful for checking the SVE port on an |
| x86 development machine.</p> |
| <p>This is not an officially supported Google product. Contact: |
| <a class="reference external" href="mailto:janwas%40google.com">janwas<span>@</span>google<span>.</span>com</a></p> |
| </div> |
| </div> |
| |
| |
| </div> |
| </div> |
| <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> |
| <a href="index.html" class="btn btn-neutral float-left" title="Highway, a C++ library that provides portable SIMD/vector intrinsics" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> |
| <a href="quick_reference.html" class="btn btn-neutral float-right" title="API synopsis / quick reference" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> |
| </div> |
| |
| <hr/> |
| |
| <div role="contentinfo"> |
| <p>© Copyright Apache 2.</p> |
| </div> |
| |
| Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a |
| <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> |
| provided by <a href="https://readthedocs.org">Read the Docs</a>. |
| |
| |
| </footer> |
| </div> |
| </div> |
| </section> |
| </div> |
| |
| |
| <div class="rst-versions" data-toggle="rst-versions" role="note" aria-label="versions"> |
| <span class="rst-current-version" data-toggle="rst-current-version"> |
| <span class="fa fa-book"> Read the Docs</span> |
| |
| |
| <span class="fa fa-element"> |
| <input class="container_toggle" type="checkbox" id="switch" name="mode"> |
| <label for="switch"></label> |
| </span> |
| |
| v: test_904484786 |
| <span class="fa fa-caret-down"></span> |
| </span> |
| <div class="rst-other-versions"> |
| |
| <dl> |
| <dt>Languages</dt> |
| |
| <strong> |
| <dd><a href="/highway/en/test_904484786/">en</a></dd> |
| </strong> |
| |
| |
| <dd><a href="/highway/zh/test_904484786/">zh</a></dd> |
| |
| |
| </dl> |
| |
| |
| <dl> |
| <dt>Versions</dt> |
| |
| |
| <dd><a href="/highway/en/disable_w32_warning/">disable_w32_warning</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/master/">master</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_407341568/">test_407341568</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_427688866/">test_427688866</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_443523054/">test_443523054</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_473247507/">test_473247507</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_516796152/">test_516796152</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_578459068/">test_578459068</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_578806572/">test_578806572</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_619132370/">test_619132370</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_620864942/">test_620864942</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_632429607/">test_632429607</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_684398826/">test_684398826</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_712003237/">test_712003237</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_724285438/">test_724285438</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_755425148/">test_755425148</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_807686228/">test_807686228</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_817072887/">test_817072887</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_822167715/">test_822167715</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_841781003/">test_841781003</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_874783036/">test_874783036</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_879112470/">test_879112470</a></dd> |
| |
| |
| |
| <dd><a href="/highway/en/test_891951691/">test_891951691</a></dd> |
| |
| |
| <strong> |
| <dd><a href="/highway/en/test_904484786/">test_904484786</a></dd> |
| </strong> |
| |
| </dl> |
| |
| |
| <dl> |
| <dt>Downloads</dt> |
| |
| <dd><a href="/highway/en/test_904484786/highway_en_test_904484786.epub">epub</a></dd> |
| |
| </dl> |
| |
| |
| <hr/> |
| Free document hosting provided by <a href="https://pages.github.com/">GitHub Pages</a>. |
| |
| </div> |
| </div> |
| |
| <script> |
| jQuery(function () { |
| SphinxRtdTheme.Navigation.enable(true); |
| }); |
| </script> |
| |
| <style> |
| .wy-nav-content { max-width: none; } |
| </style> |
| |
| |
| |
| </body> |
| </html> |