blob: 7d63af3a5f5cd69fecb969608a66b64e95e8b401 [file] [edit]
<!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 &mdash; 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 &#64;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 &lt;<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>&gt;`__,</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&amp;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">&amp;&amp;</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">&amp;&amp;</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&lt;float&gt;</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&lt;T,</span> <span class="pre">N&gt;</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&lt;T,</span> <span class="pre">N&gt;</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>&#160;&#160;&#160;&#160; <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 &#64;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>&#160;&#160;&#160;&#160; <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&lt;T&gt;</span></code>. Assume the loop body is given as a function
<code class="docutils literal notranslate"><span class="pre">template&lt;bool</span> <span class="pre">partial,</span> <span class="pre">class</span> <span class="pre">D&gt;</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">&lt;</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">&lt;</span><span class="n">false</span><span class="o">&gt;</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">&lt;</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">&lt;</span><span class="n">false</span><span class="o">&gt;</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">&gt;=</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">&lt;</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">&lt;=</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">&lt;</span><span class="n">false</span><span class="o">&gt;</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">&lt;</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">&lt;</span><span class="n">false</span><span class="o">&gt;</span><span class="p">(</span><span class="n">CappedTag</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="mi">1</span><span class="o">&gt;</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">&lt;=</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">&lt;</span><span class="n">false</span><span class="o">&gt;</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">&lt;</span> <span class="n">count</span><span class="p">)</span> <span class="p">{</span>
<span class="n">LoopBody</span><span class="o">&lt;</span><span class="n">true</span><span class="o">&gt;</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&#37;&#52;&#48;google&#46;com">janwas<span>&#64;</span>google<span>&#46;</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>&#169; 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>