--- title: Arm C Language Extensions version: 2024Q1 date-of-issue: 11 April 2024 # LaTeX specific variables copyright-text: "Copyright: see section \\texorpdfstring{\\nameref{copyright}}{Copyright}." draftversion: true # Jekyll specific variables header_counter: true toc: true --- * TOC {:toc} # Preface ## Abstract This document specifies the Arm C Language Extensions to enable C/C++ programmers to exploit the Arm architecture with minimal restrictions on source code portability. ## Keywords ACLE, ABI, C, C++, compiler, armcc, gcc, intrinsic, macro, attribute, Neon, SIMD, SVE, SVE2, atomic ## Latest release and defects report For the latest release of this document, see the [ACLE project on GitHub](https://github.com/ARM-software/acle). Please report defects in this specification to the [issue tracker page on GitHub](https://github.com/ARM-software/acle/issues). ## License This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License. To view a copy of this license, visit or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. Grant of Patent License. Subject to the terms and conditions of this license (both the Public License and this Patent License), each Licensor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Licensed Material, where such license applies only to those patent claims licensable by such Licensor that are necessarily infringed by their contribution(s) alone or by combination of their contribution(s) with the Licensed Material to which such contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Licensed Material or a contribution incorporated within the Licensed Material constitutes direct or contributory patent infringement, then any licenses granted to You under this license for that Licensed Material shall terminate as of the date such litigation is filed. ## About the license As identified more fully in the [License](#license) section, this project is licensed under CC-BY-SA-4.0 along with an additional patent license. The language in the additional patent license is largely identical to that in Apache-2.0 (specifically, Section 3 of Apache-2.0 as reflected at ) with two exceptions. First, several changes were made related to the defined terms so as to reflect the fact that such defined terms need to align with the terminology in CC-BY-SA-4.0 rather than Apache-2.0 (e.g., changing “Work” to “Licensed Material”). Second, the defensive termination clause was changed such that the scope of defensive termination applies to “any licenses granted to You” (rather than “any patent licenses granted to You”). This change is intended to help maintain a healthy ecosystem by providing additional protection to the community against patent litigation claims. ## Contributions Contributions to this project are licensed under an inbound=outbound model such that any such contributions are licensed by the contributor under the same terms as those in the LICENSE file. We do not require copyright assignment. The original contributor will retain the copyright. ## Trademark notice The text of and illustrations in this document are licensed by Arm under a Creative Commons Attribution–Share Alike 4.0 International license ("CC-BY-SA-4.0”), with an additional clause on patents. The Arm trademarks featured here are registered trademarks or trademarks of Arm Limited (or its subsidiaries) in the US and/or elsewhere. All rights reserved. Please visit for more information about Arm’s trademarks. ## Copyright * Copyright 2011-2024 Arm Limited and/or its affiliates . * Copyright 2022 Google LLC. ## About this document ### Change control #### Current Status and Anticipated Changes The following support level definitions are used by the ACLE specifications: **Release** Arm considers this specification to have enough implementations, which have received sufficient testing, to verify that it is correct. The details of these criteria are dependent on the scale and complexity of the change over previous versions: small, simple changes might only require one implementation, but more complex changes require multiple independent implementations, which have been rigorously tested for cross-compatibility. Arm anticipates that future changes to this specification will be limited to typographical corrections, clarifications and compatible extensions. **Beta** Arm considers this specification to be complete, but existing implementations do not meet the requirements for confidence in its release quality. Arm might need to make incompatible changes if issues emerge from its implementation. **Alpha** The content of this specification is a draft, and Arm considers the likelihood of future incompatible changes to be significant. All content in this document is at the **Release** quality level, unless a different support level is specified in the text. #### Change history | **Issue** | **Date** | **By** | **Change** | | ------------ | ----------------- | ------ | -------------------------------------------------------------------------------------------------------------------- | | A | 11/11/11 | AG | First release | | B | 13/11/13 | AG | Version 1.1. Editorial changes. Corrections and completions to intrinsics as detailed in 3.3. Updated for C11/C++11. | | C | 09/05/14 | TB | Version 2.0. Updated for Armv8 AArch32 and AArch64. | | D | 24/03/16 | TB | Version 2.1. Updated for Armv8.1 AArch32 and AArch64. | | E | 02/06/17 | Arm | Version ACLE Q2 2017. Updated for Armv8.2-A and Armv8.3-A. | | F | 30/04/18 | Arm | Version ACLE Q2 2018. Updated for Armv8.4-A. | | G | 30/03/19 | Arm | Version ACLE Q1 2019. Updated for Armv8.5-A and MVE. Various bugfixes. | | H | 30/06/19 | Arm | Version ACLE Q2 2019. Updated for TME and more Armv8.5-A intrinsics. Various bugfixes. | | ACLE Q3 2019 | 30/09/19 | Arm | Version ACLE Q3 2019. | | ACLE Q4 2019 | 31/12/19 | Arm | Version ACLE Q4 2019. | | ACLE Q2 2020 | 31/05/20 | Arm | Version ACLE Q2 2020. | | ACLE Q3 2020 | 31/10/20 | Arm | Version ACLE Q3 2020. | | 2021Q2 | 02 July 2021 | Arm | Version ACLE Q2 2021. Open source version. NFCI. | | 2021Q3 | 30 September 2021 | Arm | Minor re-wording. NFCI. | | 2021Q4 | 11 January 2022 | Arm | See [Changes between ACLE Q3 2021 and ACLE Q4 2021](#changes-between-acle-q3-2021-and-acle-q4-2021) | | 2022Q1 | 06 April 2022 | Arm | See [Changes between ACLE Q4 2021 and ACLE Q1 2022](#changes-between-acle-q4-2021-and-acle-q1-2022) | | 2022Q2 | 01 Jul 2022 | Arm | See [Changes between ACLE Q1 2021 and ACLE Q2 2022](#changes-between-acle-q1-2022-and-acle-q2-2022) | | 2022Q4 | 23 November 2022 | Arm | See [Changes between ACLE Q2 2022 and ACLE Q4 2022](#changes-between-acle-q2-2022-and-acle-q4-2022) | | 2023Q2 | 04 August 2023 | Arm | See [Changes between ACLE Q4 2022 and ACLE Q2 2023](#changes-between-acle-q4-2022-and-acle-q2-2023) | | 2024Q1 | 11 April 2024 | Arm | See [Changes between ACLE Q2 2023 and ACLE Q1 2024](#changes-between-acle-q2-2023-and-acle-q1-2024) | #### Changes between ACLE Q2 2017 and ACLE Q2 2018 Most changes in ACLE Q2 2018 are updates to support features introduced in Armv8.3-A [[ARMARMv83]](#ARMARMv83). Support is added for the Complex addition and Complex MLA intrinsics. Armv8.4-A [[ARMARMv84]](#ARMARMv84). Support is added for the Dot Product intrinsics. #### Changes between ACLE Q2 2018 and ACLE Q1 2019 * Support added for features introduced in Armv8.5-A [[ARMARMv85]](#ARMARMv85) (including the MTE extension). * Support added for MVE [[MVE-spec]](#MVE-spec) from the Armv8.1-M architecture. * Support added for Armv8.4-A half-precision extensions through Neon intrinsics. * Added feature detection macro for LSE atomic operations. * Added floating-point versions of intrinsics to access coprocessor registers. #### Changes between ACLE Q1 2019 and ACLE Q2 2019 * Support added for TME features. * Support added for rounding intrinsics from Armv8.5-A [[ARMARMv85]](#ARMARMv85). #### Changes between ACLE Q2 2019 and ACLE Q3 2019 * Support added for Armv8.6-A features. * Support added for random number instruction intrinsics from Armv8.5-A [[ARMARMv85]](#ARMARMv85). #### Changes between ACLE Q3 2019 and ACLE Q4 2019 * BETA support for the Custom Datapath Extension. * MVE intrinsics updates and fixes. * Feature macros for Pointer Authentication and Branch Target Identification. #### Changes between ACLE Q4 2019 and ACLE Q2 2020 * Updates to CDE intrinsics. * Allow some Neon intrinsics previously available in A64 only in A32 as well. #### Changes between ACLE Q2 2020 and ACLE Q3 2020 * Add support for features introduced in the Armv8.7-a architecture update. * Fix allowed values for __ARM_FEATURE_CDE_COPROC macro. #### Changes between ACLE Q2 2021 and ACLE Q3 2021 * Fixed FP16 format description at [Half-precision floating-point](#half-precision-floating-point). * Fixed the description of `vmul_lane_u16` at [Concepts](#neon-intrinsics-concepts). #### Changes between ACLE Q3 2021 and ACLE Q4 2021 * Updated copyright statement in section [Copyright](#copyright). * Introduced `__ARM_FEATURE_PAUTH` and `__ARM_FEATURE_BTI` in sections [Pointer Authentication](#pointer-authentication) and [Branch Target Identification](#branch-target-identification) respectively. * Fixed the changelog of 2021Q3, as is was missing the mentioning of the intrinsic `vmul_lane_u16` in the second item. * Fixed item lists rendering in [M-profile Vector Extension](#m-profile-vector-extension-mve-intrinsics). * Fixed superfluous and broken backticks in code examples throughout. * Added reference to the *Cortex-M Security Extension (CMSE)* specifications in [Cortex-M Security Extension (CMSE)](#cortex-m-security-extension-cmse). * Added specification for [NEON-SVE Bridge](#neon-sve-bridge) and [NEON-SVE Bridge macros](#neon-sve-bridge-macros). * Added feature detection macro for the memcpy family of memory operations (MOPS) at [memcpy family of memory operations standarization instructions - MOPS](#memcpy-family-of-memory-operations-standarization-instructions---mops) * Added intrinsic for the memcpy family of memory operations (MOPS) at [memcpy family of operations intrinsics - MOPS](#memcpy-family-of-operations-intrinsics---mops) * Converted document sources from reStructuredText (`.rst`) to Markdown (`.md`). The tool [`pandoc`](https://pandoc.org/) is now used to render the PDF of the specs. The PDF is rendered using the standard layout used in Arm specifications. * Updated the section links in [Changes between ACLE Q2 2021 and ACLE Q3 2021](#changes-between-acle-q2-2021-and-acle-q3-2021) by using the actual section title. #### Changes between ACLE Q4 2021 and ACLE Q1 2022 * Updated the description of the `__arm_mops_memset_tag` intrinsic in [memcpy family of operations intrinsics - MOPS](#memcpy-family-of-operations-intrinsics---mops) to require both the `__ARM_FEATURE_MOPS` and `__ARM_FEATURE_MEMORY_TAGGING` feature macros. * Fixed minor formatting errors throughout. * Replaced link text such as “sec-…” and “ssec-…” with section titles. * Reorganized the presentation of [Feature test macros](#feature-test-macros). Also: * Generalized some AArch32-specific text to AArch64. * Added more cross-references to the descriptions of the macros. * Used embedded links for the [list of predefined macros](#summary-of-predefined-macros) and fixed some misdirected links. Resorted the list into alphabetical order. * Reorganized the [Intrinsics](#intrinsics) and [Header files](#header-files) sections. * Added a description of [``](#arm_neon_sve_bridge.h) to the [Header files](#header-files) section. * In [Data types](#data-types), clarified that `__fp16` and `__bf16` are predefined types whereas vector types like `int32x4_t` are not. * Moved the [Future directions](#future-directions) chapter to the end. * Added a description of support levels in [Current Status and Anticipated Changes](#current-status-and-anticipated-changes). * Support added for [Function Multi Versioning](#function-multi-versioning). * The sections [AES extension](#aes-extension), [SHA2 extension](#sha2-extension) and [SHA512 extension](#sha512-extension) have been reworded for clarity, by specifying the `FEAT_*` tag they refer to from the Arm Architectural Reference Manual. * Sorted the items in [References](#references). * Changed the wording of **Beta** in [Current Status and Anticipated Changes](#current-status-and-anticipated-changes). * Sorted the table in [Terms and abbreviations](#terms-and-abbreviations). * Formatted `memcpy`, `memmove` and `memset` with fixed-width font all throughout the document. * Minor rewording for: * [Introduction](#introduction) section of [memcpy family of operations intrinsics - MOPS](#memcpy-family-of-operations-intrinsics---mops). * [Procedure calls and the Q / GE bits](#procedure-calls-and-the-q-ge-bits). * [Custom calling conventions](#custom-calling-conventions) - use a bulleted list for the examples. No functional change intended. * Reordered the sections in [Change history](#change-history) in chronological order. #### Changes between ACLE Q1 2022 and ACLE Q2 2022 * Added [support for SVE and SVE2](#arm_sve.h). This incorporates the final 00bet6 version of the separate beta document [Arm C Language Extensions for SVE](https://developer.arm.com/architectures/system-architectures/software-standards/acle), except that the optional feature `__ARM_FEATURE_SVE_NONMEMBER_OPERATORS` has been removed. The SVE and SVE2 support is now at “release” rather than beta quality and the separate beta document is no longer maintained. * Added section [Scalable Vector Extension procedure call standard attribute](#scalable-vector-extension-procedure-call-standard-attribute) * Fixes for [Function Multi Versioning](#function-multi-versioning): * typo in `FEAT_DPB2`. * added `FEAT_LS64*`. #### Changes between ACLE Q2 2022 and ACLE Q4 2022 * Added [**Alpha**](#current-status-and-anticipated-changes) [support for SME](#arm_sme.h). * Added feature detection macro `__ARM_FEATURE_RCPC` for RCpc (Release Consistent processor consistent) model at [RCpc](#rcpc). * Added two new valid values to the [SVE feature macros](#scalable-vector-extension-sve): * `__ARM_FEATURE_SVE_VECTOR_OPERATORS=2` * `__ARM_FEATURE_SVE_PREDICATE_OPERATORS=2` * Fixes for [Function Multi Versioning](#function-multi-versioning): * Added missing features of `ID_AA64ISAR1_EL1` and `ID_AA64ISAR2_EL1`. * Renamed the feature macro to `__HAVE_FUNCTION_MULTI_VERSIONING` * Added some clarifications. #### Changes between ACLE Q4 2022 and ACLE Q2 2023 * Added SLC as a valid Cache Level for the Memory prefetch intrinsics. * Added [support for 128-bit system registers](#special-register-intrinsics), including two intrinsics for accessing them (`__rsr128` and `__wsr128`), and a feature macro to detect if they are available (`__ARM_FEATURE_SYSREG128`). * Added support for FEAT_LRCPC3 LDAP1/STL1 intrinsics and `__ARM_FEATURE_RCPC`. * Corrected the mandatory architecture versions for FEAT_LRCPC and FEAT_LRCPC2. * Corrected references to `-pedantic` flag. * Fixed typos. * Fixes for [Function Multi Versioning](#function-multi-versioning): * Renamed features to `sme-f64f64` and `sme-i16i64` * Corrected register name to `ID_AA64SMFR0_EL1.I16I64` * Removed incorrect optimisation remark in [CMSE](#CMSE-ACLE)'s floating-point register clearing. * Removed incorrect information about the floating-point ABI used in [CMSE](#CMSE-ACLE)'s Arguments on the stack and floating point handling. * Corrected description and example in [CMSE](#CMSE-ACLE)'s section about non-secure function pointers. * Added a requirement on [`arm_new_za`] to set the initial contents of ZA to zero. #### Changes between ACLE Q2 2023 and ACLE Q1 2024 * Changed the definition of the `__ARM_ACLE` macro to reflect the current versioning scheme. * Added `__ARM_ACLE_VERSION` to express a given ACLE version. * Combined the SME `slice_base` and `slice_offset` arguments into a single `slice` argument. * Added the [Keyword attributes](#keyword-attributes) section. * Changed the [SME language extensions](#sme-language-extensions-and-intrinsics) to use keyword attributes instead of GNU-style attributes. * Added description of SVE reinterpret intrinsics. * Changes and fixes for [Function Multi Versioning](#function-multi-versioning): * Combination of attributes `target_version` and `target_clones` is allowed. * Clarify the existance of a single default version across all translation units with the explicitly provided version being the preferred in case `target_version` and `target_clones` are mixed. * Emphasise that all instances of the versions share the same calling convention. * Changed the mangling rules [Name mangling](#name-mangling), such that feature names are appended in lexicographic order, not in priority order. * Mangled names contain a unique set of features (no duplicates). * Added [MOPS](#memcpy-family-of-operations-intrinsics---mops). * Changed name mangling of the default version. * Aligned priorities to account for feature dependencies. * Introduced alternative names (aliases) `rdma` for `rdm`. * Corrected FEAT_BTI feature register value. * Introduced the `__ARM_FEATURE_PAUTH_LR` feature macro in section [Pointer Authentication](#pointer-authentication) to indicate target support for the Armv9.5-A PAC Enhancements. * Introduced a new value to the `__ARM_FEATURE_PAC_DEFAULT` macro to indicate the use of PC as a diversifier for [Pointer Authentication](#pointer-authentication). * Added a [State management](#state-management) section, replacing the `__arm_shared_za`, `__arm_new_za`, and `__arm_preserves_za` attributes in the previous Alpha SME spec. * Changed the status of the SME ACLE from Alpha to Beta. #### Changes for next release ### References This document refers to the following documents. * AAPCS Arm, [Application Binary Interface for the Arm Architecture](https://developer.arm.com/products/architecture/system-architectures/software-standards/abi) * AAPCS64 Arm, [Application Binary Interface for the Arm Architecture](https://developer.arm.com/products/architecture/system-architectures/software-standards/abi) * ARMARM Arm, Arm Architecture Reference Manual (7-A / 7-R), Arm DDI 0406C * ARMARMv8 Arm, Armv8-A Reference Manual (Issue A.b), Arm DDI0487A.B * ARMARMv81 Arm, Armv8.1 Extension, [The ARMv8-A architecture and its ongoing development](http://community.arm.com/groups/processors/blog/2014/12/02/the-armv8-a-architecture-and-its-ongoing-development) * ARMARMv82 Arm, Armv8.2 Extension, [Armv8-A architecture evolution](https://community.arm.com/groups/processors/blog/2016/01/05/armv8-a-architecture-evolution) * ARMARMv83 Arm, Armv8.3 Extension, [Armv8-A architecture: 2016 additions](https://community.arm.com/processors/b/blog/posts/armv8-a-architecture-2016-additions) * ARMARMv84 Arm, Armv8.4 Extension, [Introducing 2017’s extensions to the Arm Architecture](https://community.arm.com/processors/b/blog/posts/introducing-2017s-extensions-to-the-arm-architecture) * ARMARMv85 Arm, Armv8.5 Extension, [Arm A-Profile Architecture Developments 2018: Armv8.5-A](https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/arm-a-profile-architecture-2018-developments-armv85a) * ARMv7M Arm, Arm Architecture Reference Manual (7-M), Arm DDI 0403C * BA Arm, EABI Addenda and Errata Build Attributes, Arm IHI 0045C * Bfloat16 Arm, [BFloat16 processing for Neural Networks on Armv8-A](https://community.arm.com/developer/ip-products/processors/b/ml-ip-blog/posts/bfloat16-processing-for-neural-networks-on-armv8_2d00_a) * C11 ISO, Standard C (based on draft N1570), ISO/IEC 9899:2011 * C99 ISO, Standard C (C99), ISO 9899:1999 * CFP15 ISO/IEC, Floating point extensions for C, ISO/IEC TS 18661-3 * CMSE-ACLE Arm, [Arm®v8-M Security Extensions: Requirements on Development Tools](https://developer.arm.com/documentation/ecm0359818/latest) * CPP11 ISO, Standard C++ (based on draft N3337), ISO/IEC 14882:2011 * CPP14 ISO, Standard C++ (based on draft N3797), ISO/IEC 14882:2014 * G.191 ITU-T, Software Tool Library 2005 User's Manual, T-REC-G.191-200508-I * GCC GNU/FSF, [GNU C Compiler Collection](http://gcc.gnu.org/onlinedocs) * IA-64 Intel, Intel Itanium Processor-Specific ABI, 245370-003 * IEEE-FP IEEE, IEEE Floating Point, IEEE 754-2008 * MVE Arm, [MVE Intrinsics](https://developer.arm.com/architectures/instruction-sets/simd-isas/helium/mve-intrinsics) * MVE-spec Arm, Arm v8-M Architecture Reference Manual, Arm DDI0553B.F * Neon Arm, [Neon Intrinsics](https://developer.arm.com/technologies/neon/intrinsics) * POSIX IEEE / TOG, The Open Group Base Specifications, IEEE 1003.1 * Warren 8. Warren, Hacker's Delight, pub. Addison-Wesley 2003 * cxxabi [Itanium C++ ABI](https://itanium-cxx-abi.github.io/cxx-abi/) ### Terms and abbreviations This document uses the following terms and abbreviations. | **Term** | **Meaning** | | ---------------- | -------------------------------------------------------------------------------------------- | | AAPCS | Arm Procedure Call Standard, part of the ABI, defined in [[AAPCS]](#AAPCS). | | ABI | Arm Application Binary Interface. | | ACLE | Arm C Language Extensions, as defined in this document. | | Advanced SIMD | A 64-bit/128-bit SIMD instruction set defined as part of the Arm architecture. | | FFR | The SVE first-fault register. | | FFRT | The SVE “first-fault register token”. This is a conceptual construct that forms part of the ACLE model of first-faulting and non-faulting loads; see [First-faulting and non-faulting loads](#first-faulting-and-non-faulting-loads) for details. | | ILP32 | A 32-bit address mode where long is a 32-bit type. | | LLP64 | A 64-bit address mode where long is a 32-bit type. | | LP64 | A 64-bit address mode where long is a 64-bit type. | | Neon | An implementation of the Arm Advanced SIMD extensions. | | SIMD | Any instruction set that operates simultaneously on multiple elements of a vector data type. | | sizeless type | A C and C++ type that can be used to create objects, but that has no measurable size; see [Sizeless types](#sizeless-types) for details. | | SVE | The Armv8-A Scalable Vector Extension. Also used more generally to include SVE2 and other SVE extensions. | | SVE2 | An Armv9-A extension of SVE. | | SVL | Streaming Vector Length; that is, the number of bits in an SVE vector type like ``svint32_t`` when the processor is in [streaming mode](#streaming-mode) | | SVL.B | As for SVL, but measured in bytes rather than bits | | Thumb | The Thumb instruction set extension to Arm. | | VG | The number of 64-bit elements (“vector granules”) in an SVE vector. | | VFP | The original Arm non-SIMD floating-point instruction set. | | build attributes | Object build attributes indicating configuration, as defined in [[BA]](#BA). | | word | A 32-bit quantity, in memory or a register. | ### Terms used to specify C and C++ semantics The following terms are used to specify C and C++ semantics: **abstract machine** > The conceptual machine that the C and C++ language standards use to define > the behavior of programs. **evaluated call** > A call that does not occur in an “unevaluated operand”; > see section `[expr.context]` in the C++ standard for details. > > For example, any calls that occur in the operand of a `sizeof` > expression are not evaluated. **external linkage** > A function has “external linkage” if there is a single definition that can be > referenced by name from more than one translation unit. See `[basic.link]` > in the C++ standard for more details. > > As noted in [Intrinsics](#intrinsics), it is unspecified whether ACLE > intrinsics are functions and, if so, what linkage they have. However, > certain ACLE support functions are defined to have external linkage. **ill-formed** programs or pieces of programs > Programs or pieces of programs that violate a rule due to their static > construction rather than due to their runtime behavior. > > Ill-formed programs should usually be rejected with at least one > diagnostic. However, there are some ill-formed C++ constructs for which > “no diagnostic is required”; see the `[intro]` section of the C++ > standard for details. Many of these constructs could in principle > use ACLE features. > > In order to cope with such cases, ACLE does not say when > ill-formed programs should be rejected. However, from a > quality-of-implementation perspective, it is better to reject > ill-formed programs wherever possible. **unprototyped functions** > In early versions of C, it was possible to call a function without > declaring it first. The function was then assumed to return an `int`. > For example, this was a valid complete translation unit: > > ``` c > int x() { return some_func(1, 2.0, "apples"); } > ``` > > It was also possible to declare a function's return type without specifying > its argument types. For example: > > ``` c > double another_func(); > double f() { return another_func(1.0, 2, "oranges"); } > ``` > > Functions such as `some_func` and `another_func` are referred to as > (K&R-style) “unprototyped” functions. The first C standard categorized > these functions as an obsolescent feature and C18 removed all remaining > support for them. ## Conventions Most SVE ACLE intrinsics have two names: a longer unique name and a shorter overloaded alias. The convention adopted in this document is to enclose characters in square brackets if they are only present in the longer name. For example: ``` c svclz[_u16]_m ``` refers to an intrinsic whose full name is `svclz_u16_m` and whose overloaded alias is `svclz_m`. ## Scope The Arm C Language Extensions (ACLE) specification specifies source language extensions and implementation choices that C/C++ compilers can implement in order to allow programmers to better exploit the Arm architecture. The extensions include: * Predefined macros that provide information about the functionality of the target architecture. * Intrinsic functions. * Attributes that can be applied to functions, data and other entities. This specification does not standardize command-line options, diagnostics or other external behavior of compilers. The intended users of this specification are: * Application programmers wishing to adapt or hand-optimize applications and libraries for Arm targets. * System programmers needing low-level access to Arm targets beyond what C/C++ provides for. * Compiler implementors, who will implement this specification. * Implementors of IDEs, static analysis and other similar tools who wish to deal with the C/C++ source language extensions when encountered in source code. ACLE is not a hardware abstraction layer (HAL), and does not specify a library component but it may make it easier to write a HAL or other low-level library in C rather than assembler. ## Cortex-M Security Extension (CMSE) ACLE support for the Cortex-M Security Extension (CMSE) is defined in *Arm®v8-M Security Extensions: Requirements on Development Tools* document [CMSE-ACLE](#CMSE-ACLE). # Introduction The Arm architecture includes features that go beyond the set of operations available to C/C++ programmers. The intention of the Arm C Language Extensions (ACLE) is to allow the creation of applications and middleware code that is portable across compilers, and across Arm architecture variants, while exploiting the advanced features of the Arm architecture. The design principles for ACLE can be summarized as: * Be implementable in (or as an addition to) current C/C++ implementations. * Build on and standardize existing practice where possible. ACLE incorporates some language extensions introduced in the GCC C compiler. Current GCC documentation [[GCC]](#GCC) can be found at . Formally it should be assumed that ACLE refers to the documentation for GCC 4.5.1: . Some of the ACLE extensions are not specific to the Arm architecture but have proven to be of particular benefit in low-level and systems programming; examples include features for controlling the alignment and packing of data, and some common operations such as word rotation and reversal. As and when features become available in international standards (and implementations), Arm recommends that you use these in preference to ACLE. When implementations are widely available, any ACLE-specific features can be expected to be deprecated. ## Portable binary objects In AArch32, the *ABI for the Arm Architecture* defines a set of build attributes [[BA]](#BA). These attributes are intended to facilitate generating cross-platform portable binary object files by providing a mechanism to determine the compatibility of object files. In AArch64, the ABI does not define a standard set of build attributes and takes the approach that binaries are, in general, not portable across platforms. References to build attributes in this document should be interpreted as applying only to AArch32. # C language extensions ## Data types This section overlaps with the specification of the Arm Procedure Call Standard, particularly [[AAPCS]](#AAPCS) (4.1). ACLE extends some of the guarantees of C, allowing assumptions to be made in source code beyond those permitted by Standard C. * Plain char is unsigned, as specified in the ABI [[AAPCS]](#AAPCS) and [[AAPCS64]](#AAPCS64) (7.1.1). * When pointers are 32 bits, the long type is 32 bits (ILP32 model). * When pointers are 64 bits, the long type may be either 64 bits (LP64 model) or 32 bits (LLP64 model). ACLE extends C by providing some types not present in Standard C and defining how they are dealt with by the AAPCS. These types fall into two groups: * types that are defined by [header files](#header-files) * types that are predefined by the implementation, so that no header file needs to be included to make use of them The former group includes things like [vector data types](#vector-data-types), which are defined by the header file [``](#arm_neon.h). The predefined types are: * The `__fp16` type for 16-bit floating-point values (see [Half-precision floating-point](#half-precision-floating-point)). * The `__bf16` type for 16-bit brain floating-point values (see [Half-precision brain floating-point](#half-precision-brain-floating-point)). ### Implementation-defined type properties ACLE and the Arm ABI allow implementations some freedom in order to conform to long-standing conventions in various environments. It is suggested that implementations set suitable defaults for their environment but allow the default to be overridden. The signedness of a plain int bit-field is implementation-defined. Whether the underlying type of an enumeration is minimal or at least 32-bit, is implementation-defined. The predefined macro `__ARM_SIZEOF_MINIMAL_ENUM` should be defined as 1 or 4 according to the size of a minimal enumeration type such as `enum { X=0 }`. An implementation that conforms to the Arm ABI must reflect its choice in the `Tag_ABI_enum_size build` attribute. `wchar_t` may be 2 or 4 bytes. The predefined macro `__ARM_SIZEOF_WCHAR_T` should be defined as the same number. An implementation that conforms to the Arm ABI must reflect its choice in the `Tag_ABI_PCS_wchar_t` build attribute. ## Predefined macros Several predefined macros are defined. Generally these define features of the Arm architecture being targeted, or how the C/C++ implementation uses the architecture. These macros are detailed in [Feature test macros](#feature-test-macros). All ACLE predefined macros start with the prefix `__ARM`. ## Keyword attributes This section is in [**Beta** state](#current-status-and-anticipated-changes) and may change or be extended in the future. ACLE adds several non-standard keywords to C and C++. These keywords all start with the prefix `__arm_`. (However, not everything that starts with `__arm_` is a keyword.) The keywords are modeled after standard `[[…]]` attributes and fulfill a similar role to them. However, the C++ standard says that “any [non-standard attribute] that is not recognized by the implementation is ignored” `[dcl.attr.grammar]`. It is therefore not appropriate to use standard attributes for properties that affect the type system, that affect the binary interface of the generated code, or that must be honored for other reasons. ACLE uses keywords for some of these properties instead. The keywords are therefore known as “keyword attributes”. A keyword attribute can appear wherever a standard `[[…]]` attribute can appear. Following the terminology of the C++ standard, a keyword attribute “appertains” to whatever a standard attribute would appertain to. For example, consider the placeholders A, B, C and D in the following function declaration: ``` c /*A*/ void /*B*/ f /*C*/ (void) /*D*/; ``` Here: * Attributes in position A appertain to the function declaration `f`. * Attributes in position B appertain to the return type (`void`). * Attributes in position C appertain to the function declaration `f`, as for A. * Attributes in position D appertain to the type of `f` (`void ()(void)`). Position A is preferred over position C for ACLE code. This is because position A can also be used for GNU-style attributes, whereas position C cannot. The table below lists all the ACLE keyword attributes. The “Target” column says what the keyword is allowed to appertain to. For example, a function type keyword can appear in position D above, but it cannot appear in positions A, B or C. Keyword attributes are only guaranteed to be supported by compilers that predefine the associated macro to a nonzero value. | **Name** | **Target** | **Predefined macro** | | ----------------------------------------------------------- | --------------------- | --------------------------------- | | [`__arm_locally_streaming`](#arm_locally_streaming) | function declaration | `__ARM_FEATURE_LOCALLY_STREAMING` | | [`__arm_in`](#ways-of-sharing-state) | function type | Argument-dependent | | [`__arm_inout`](#ways-of-sharing-state) | function type | Argument-dependent | | [`__arm_new`](#arm_new) | function declaration | Argument-dependent | | [`__arm_out`](#ways-of-sharing-state) | function type | Argument-dependent | | [`__arm_preserves`](#ways-of-sharing-state) | function type | Argument-dependent | | [`__arm_streaming`](#arm_streaming) | function type | `__ARM_FEATURE_SME` | | [`__arm_streaming_compatible`](#arm_streaming_compatible) | function type | `__ARM_FEATURE_SME` | Using a keyword attribute multiple times is equivalent to using it once. ## Intrinsics ACLE standardizes intrinsics to access various features of the Arm ® architecture. It also standardizes a set of [header files](#header-files) that provide access to these intrinsics. Whether intrinsics are macros, functions or built-in operators is unspecified. For example: * It is unspecified whether applying #undef to an intrinsic removes the name from visibility * It is unspecified whether it is possible to take the address of an intrinsic However, each argument must be evaluated at most once. So this definition is acceptable: ``` c #define __rev(x) __builtin_bswap32(x) ``` but this is not: ``` c #define __rev(x) ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | \ (((x) & 0xff0000) >> 8) | ((x) >> 24)) ``` ### Constant arguments to intrinsics Some intrinsics may require arguments that are constant at compile-time, to supply data that is encoded into the immediate fields of an instruction. Typically, these intrinsics require an integral-constant-expression in a specified range, or sometimes a string literal. An implementation should produce a diagnostic if the argument does not meet the requirements. ## Header files ACLE standardizes various header files that provide access to [intrinsics](#intrinsics) and their associated data types. It also standardizes [feature test macros](#feature-test-macros) that indicate which header files are available. Some architecture features have a dedicated header file; for example, [``](#arm_neon.h) provides access to the [Advanced SIMD (Neon) intrinsics](#advanced-simd-neon-intrinsics). [`arm_acle.h`](#arm_acle.h) provides a catch-all for intrinsics that do not belong to a more specific header file. These headers behave as standard library headers; repeated inclusion has no effect beyond the first include. Except where noted otherwise, it is unspecified whether the ACLE headers include the standard headers ``, `` or ``. However, the ACLE headers will not define the standard type names (for example `uint32_t`) except by inclusion of the standard headers. Arm recommends that you include the standard headers explicitly if the associated types and macros are needed. In C++, the following source code fragments are expected to work correctly: ``` c #include // UINT64_C not defined here since we did not set __STDC_FORMAT_MACROS ... #include ``` and: ``` c #include ... #define __STDC_FORMAT_MACROS #include // ... UINT64_C is now defined ``` ### `` `` provides access to intrinsics that do not belong to the more specific header files below. These intrinsics are in the C implementation namespace and begin with double underscores. It is unspecified whether they are available without the header being included. The `__ARM_ACLE` macro should be tested before including the header: ``` c #ifdef __ARM_ACLE #include #endif /* __ARM_ACLE */ ``` ### `` `` is provided to define the scalar 16-bit floating point arithmetic intrinsics. As these intrinsics are in the user namespace, an implementation would not normally define them until the header is included. The `__ARM_FEATURE_FP16_SCALAR_ARITHMETIC` feature macro should be tested before including the header: ``` c #ifdef __ARM_FEATURE_FP16_SCALAR_ARITHMETIC #include #endif /* __ARM_FEATURE_FP16_SCALAR_ARITHMETIC */ ``` ### `` `` is provided to define the 16-bit brain floating point arithmetic intrinsics. As these intrinsics are in the user namespace, an implementation would not normally define them until the header is included. The `__ARM_FEATURE_BF16` feature macro should be tested before including the header: ``` c #ifdef __ARM_FEATURE_BF16 #include #endif /* __ARM_FEATURE_BF16 */ ``` When `__ARM_BF16_FORMAT_ALTERNATIVE` is defined to `1` the only scalar instructions available are conversion intrinsics between `bfloat16_t` and `float32_t`. These instructions are: * `vcvth_bf16_f32` (convert float32_t to bfloat16_t) * `vcvtah_f32_bf16` (convert bfloat16_t to float32_t) ### `` `` is provided to define the [Advanced SIMD (Neon) intrinsics](#advanced-simd-neon-intrinsics) and associated [data types](#vector-data-types). As these intrinsics and data types are in the user namespace, an implementation would not normally define them until the header is included. The `__ARM_NEON` macro should be tested before including the header: ``` c #ifdef __ARM_NEON #include #endif /* __ARM_NEON */ ``` Including `` will also cause the following header files to be included, if the header files are available: * [``](#arm_fp16.h) * [``](#arm_bf16.h) ### `` `` defines data types and intrinsics for SVE and its extensions; see [SVE language extensions and intrinsics](#sve-language-extensions-and-intrinsics) for details. You should test the `__ARM_FEATURE_SVE` macro before including the header: ``` c #ifdef __ARM_FEATURE_SVE #include #endif /* __ARM_FEATURE_SVE */ ``` Including `` also includes the following header files: * `` * `` (for C only) * [``](#arm_fp16.h) * [``](#arm_bf16.h) (if available) ### `` `` defines intrinsics for moving data between Neon and SVE vector types; see [NEON-SVE Bridge](#neon-sve-bridge) for details. The `__ARM_NEON_SVE_BRIDGE` macro should be tested before including the header: ``` c #ifdef __ARM_NEON_SVE_BRIDGE #include #endif /* __ARM_NEON_SVE_BRIDGE */ ``` Including `` will also include [``](#arm_neon.h) and [``](#arm_sve.h). ### `` `` is provided to define the [M-profile Vector Extension (MVE) intrinsics](#m-profile-vector-extension-mve-intrinsics) and associated data types. The data types occupy the user namespace. By default the intrinsics occupy both the user namespace and the `__arm_` namespace; defining `__ARM_MVE_PRESERVE_USER_NAMESPACE` will hide the definition of the user namespace variants. The `__ARM_FEATURE_MVE` macro should be tested before including the header: ``` c #if (__ARM_FEATURE_MVE & 3) == 3 #include /* MVE integer and floating point intrinsics are now available to use. */ #elif __ARM_FEATURE_MVE & 1 #include /* MVE integer intrinsics are now available to use. */ #endif ``` ### `` The specification for SME is in [**Beta** state](#current-status-and-anticipated-changes) and may change or be extended in the future. `` declares functions and defines intrinsics for SME and its extensions; see [SME language extensions and intrinsics](#sme-language-extensions-and-intrinsics) for details. The `__ARM_FEATURE_SME` macro should be tested before including the header: ``` c #ifdef __ARM_FEATURE_SME #include #endif ``` Including `` also includes [``](#arm_sve.h). ## Attributes GCC-style attributes are provided to annotate types, objects and functions with extra information, such as alignment. These attributes are defined in [Attributes and pragmas](#attributes-and-pragmas). ## Implementation strategies An implementation may choose to define all the ACLE non-Neon intrinsics as true compiler intrinsics, i.e. built-in functions. The `` header would then have no effect. Alternatively, `` could define the ACLE intrinsics in terms of already supported features of the implementation, for example compiler intrinsics with other names, or inline functions using inline assembler. ### Half-precision floating-point ACLE defines the `__fp16` type, which can be used for half-precision (16-bit) floating-point in one of two formats. The binary16 format defined in [[IEEE-FP]](#IEEE-FP), and referred to as *IEEE* format, and an alternative format, defined by Arm, which extends the range by removing support for infinities and NaNs, referred to as *alternative* format. Both formats are described in [[ARMARM]](#ARMARM) (A2.7.4), [[ARMARMv8]](#ARMARMv8) (A1.4.2). Toolchains are not required to support the alternative format, and use of the alternative format precludes use of the ISO/IEC TS 18661:3 [[CFP15]](#CFP15) `_Float16` type and the Armv8.2-A 16-bit floating-point extensions. For these reasons, Arm deprecates the use of the alternative format for half precision in ACLE. The format in use can be selected at runtime but ACLE assumes it is fixed for the life of a program. If the `__fp16` type is available, one of `__ARM_FP16_FORMAT_IEEE` and `__ARM_FP16_FORMAT_ALTERNATIVE` will be defined to indicate the format in use. An implementation conforming to the Arm ABI will set the `Tag_ABI_FP_16bit_format` build attribute. The `__fp16` type can be used in two ways; using the intrinsics ACLE defines when the Armv8.2-A 16-bit floating point extensions are available, and using the standard C operators. When using standard C operators, values of `__fp16` type promote to (at least) float when used in arithmetic operations, in the same way that values of char or short types promote to int. There is no support for arithmetic directly on `__fp16` values using standard C operators. ``` c void add(__fp16 a, __fp16 b) { a + b; /* a and b are promoted to (at least) float. Operation takes place with (at least) 32-bit precision. */ vaddh_f16 (a, b); /* a and b are not promoted. Operation takes place with 16-bit precision. */ } ``` Armv8 introduces floating point instructions to convert 64-bit to 16-bit i.e. from double to `__fp16`. They are not available in earlier architectures, therefore have to rely on emulation libraries or a sequence of instructions to achieve the conversion. Providing emulation libraries for half-precision floating point conversions when not implemented in hardware is implementation-defined. ``` c double xd; __fp16 xs = (float)xd; ``` rather than: ``` c double xd; __fp16 xs = xd; ``` In some older implementations, `__fp16` cannot be used as an argument or result type, though it can be used as a field in a structure passed as an argument or result, or passed via a pointer. The predefined macro `__ARM_FP16_ARGS` should be defined if `__fp16` can be used as an argument and result. C++ name mangling is Dh as defined in [[cxxabi]](#cxxabi), and is the same for both the IEEE and alternative formats. In this example, the floating-point addition is done in single (32-bit) precision: ``` c void add(__fp16 *z, __fp16 const *x, __fp16 const *y, int n) { int i; for (i = 0; i < n; ++i) z[i] = x[i] + y[i]; } ``` ### Relationship between `__fp16` and ISO/IEC TS 18661 ISO/IEC TS 18661-3 [[CFP15]](#CFP15) is a published extension to [[C11]](#C11) which describes a language binding for the [[IEEE-FP]](#IEEE-FP) standard for floating point arithmetic. This language binding introduces a mapping to an unlimited number of interchange and extended floating-point types, on which binary arithmetic is well defined. These types are of the form `_FloatN`, where `N` gives size in bits of the type. One instantiation of the interchange types introduced by [[CFP15]](#CFP15) is the `_Float16` type. ACLE defines the `__fp16` type as a storage and interchange only format, on which arithmetic operations are defined to first promote to a type with at least the range and precision of float. This has implications for the result of operations which would result in rounding had the operation taken place in a native 16-bit type. As software may rely on this behaviour for correctness, arithmetic operations on `__fp16` are defined to promote even when the Armv8.2-A fp16 extension is available. Arm recommends that portable software is written to use the `_Float16` type defined in [[CFP15]](#CFP15). Type conversion between a value of type `__fp16` and a value of type `_Float16` leaves the object representation of the converted value unchanged. When `__ARM_FP16_FORMAT_IEEE == 1`, this has no effect on the value of the object. However, as the representation of certain values has a different meaning when using the Arm alternative format for 16-bit floating point values [[ARMARM]](#ARMARM) (A2.7.4) [[ARMARMv8]](#ARMARMv8) (A1.4.2), when `__ARM_FP16_FORMAT_ALTERNATIVE == 1` the type conversion may introduce or remove infinity or NaN representations. Arm recommends that software implementations warn on type conversions between `__fp16` and `_Float16` if `__ARM_FP16_FORMAT_ALTERNATIVE == 1`. In an arithmetic operation where one operand is of `__fp16` type and the other is of `_Float16 type`, the `_Float16` type is first converted to `__fp16` type following the rules above, and then the operation is completed as if both operands were of `__fp16` type. [[CFP15]](#CFP15) and [[C11]](#C11) do not define vector types, however many C implementations do provide these extensions. Where they exist, type conversion between a value of type vector of `__fp16` and a value of type vector of `_Float16` leaves the object representation of the converted value unchanged. ACLE does not define vector of `_Float16` types. ### Half-precision brain floating-point ACLE defines the `__bf16` type, which can be used for half-precision (16-bit) brain floating-point in an alternative format, defined by Arm, which closely resembles the IEEE 754 single-precision floating point format. The `__bf16` type is only available when the `__ARM_BF16_FORMAT_ALTERNATIVE` feature macro is defined. When it is available it can only be used by the ACLE intrinsics ; it cannot be used with standard C operators. It is expected that arithmetic using standard C operators be used using a single-precision floating point format and the value be converted to `__bf16` when required using ACLE intrinsics. Armv8.2-A introduces floating point instructions to convert 32-bit to brain 16-bit i.e. from float to `__bf16`. They are not available in earlier architectures, therefore have to rely on emulation libraries or a sequence of instructions to achieve the conversion. Providing emulation libraries for half-precision floating point conversions when not implemented in hardware is implementation-defined. # Architecture and CPU names ## Introduction The intention of this section is to standardize architecture names, for example for use in compiler command lines. Toolchains should accept these names case-insensitively where possible, or use all lowercase where not possible. Tools may apply local conventions such as using hyphens instead of underscores. (Note: processor names, including from the Arm Cortex |reg| processor family, are used as illustrative examples. This specification is applicable to any processors implementing the Arm architecture.) ## Architecture names ### CPU architecture The recommended CPU architecture names are as specified under `Tag_CPU_arch` in [[BA]](#BA). For details of how to use predefined macros to test architecture in source code, see [Instruction set architecture and features](#instruction-set-architecture-and-features). The following table lists the architectures and the A32 and T32 instruction set versions. | **Name** | **Features** | **A32** | **T32** | **Example processor** | | --------------- | -------------------------------------------------------- | ------- | ------- | ---------------------- | | Armv4 | Armv4 | 4 | | DEC/Intel StrongARM | | Armv4T | Armv4 with Thumb instruction set | 4 | 2 | Arm7TDMI | | Armv5T | Armv5 with Thumb instruction set | 5 | 2 | Arm10TDMI | | Armv5TE | Armv5T with DSP extensions | 5 | 2 | Arm9E, Intel XScale | | Armv5TEJ | Armv5TE with Jazelle ® extensions | 5 | 2 | Arm926EJ | | Armv6 | Armv6 (includes TEJ) | 6 | 2 | Arm1136J r0 | | Armv6K | Armv6 with kernel extensions | 6 | 2 | Arm1136J r1 | | Armv6T2 | Armv6 with Thumb-2 architecture | 6 | 3 | Arm1156T2 | | Armv6Z | Armv6K with Security Extensions (includes K) | 6 | 2 | Arm1176JZ-S | | Armv6-M | T32 (M-profile) | | 2 | Cortex-M0, Cortex-M1 | | Armv7-A | Armv7 application profile | 7 | 4 | Cortex-A8, Cortex-A9 | | Armv7-R | Armv7 realtime profile | 7 | 4 | Cortex-R4 | | Armv7-M | Armv7 microcontroller profile: Thumb-2 instructions only | | 4 | Cortex-M3 | | Armv7E-M | Armv7-M with DSP extensions | | 4 | Cortex-M4 | | Armv8-A AArch32 | Armv8 application profile | 8 | 4 | Cortex-A57, Cortex-A53 | | Armv8-A AArch64 | Armv8 application profile | 8 | | Cortex-A57, Cortex-A53 | Note that there is some architectural variation that is not visible through ACLE; either because it is only relevant at the system level (for example the Large Physical Address Extension) or because it would be handled by the compiler (for example hardware divide might or might not be present in the Armv7-A architecture). ### FPU architecture For details of how to test FPU features in source code, see [Floating-point and vector hardware](#floating-point-and-vector-hardware). In particular, for testing which precisions are supported in hardware, see [Hardware floating point](#hardware-floating-point). | **Name** | **Features** | **Example processor** | | ---------------- | -------------------------------------------------- | ----------------------------------- | | `VFPv2` | VFPv2 | Arm1136JF-S | | `VFPv3` | VFPv3 | Cortex-A8 | | `VFPv3_FP16` | VFPv3 with FP16 | Cortex-A9 (with Neon) | | `VFPv3_D16` | VFPv3 with 16 D-registers | Cortex-R4F | | `VFPv3_D16_FP16` | VFPv3 with 16 D-registers and FP16 | Cortex-A9 (without Neon), Cortex-R7 | | `VFPv3_SP_D16` | VFPv3 with 16 D-registers, single-precision only | Cortex-R5 with SP-only | | `VFPv4` | VFPv4 (including FMA and FP16) | Cortex-A15 | | `VFPv4_D16` | VFPv4 (including FMA and FP16) with 16 D-registers | Cortex-A5 (VFP option) | | `FPv4_SP` | FPv4 with single-precision only | Cortex-M4.fp | ## CPU names ACLE does not standardize CPU names for use in command-line options and similar contexts. Standard vendor product names should be used. Object producers should place the CPU name in the `Tag_CPU_name` build attribute. # Feature test macros ## Introduction The feature test macros allow programmers to determine the availability of ACLE or subsets of it, or of target architectural features. This may indicate the availability of some source language extensions (for example intrinsics) or the likely level of performance of some standard C features, such as integer division and floating-point. Several macros are defined as numeric values to indicate the level of support for particular features. These macros are undefined if the feature is not present. (Aside: in Standard C/C++, references to undefined macros expand to 0 in preprocessor expressions, so a comparison such as: ``` c #if __ARM_ARCH >= 7 ``` will have the expected effect of evaluating to false if the macro is not defined.) All ACLE macros begin with the prefix `__ARM_`. All ACLE macros expand to integral constant expressions suitable for use in an #if directive, unless otherwise specified. Syntactically, they must be primary-expressions generally this means an implementation should enclose them in parentheses if they are not simple constants. ## Testing for Arm C Language Extensions `__ARM_ACLE` is defined as the version of this specification that is implemented, formatted as `{YEAR}{QUARTER}{PATCH}`. The `YEAR` segment is composed of 4 digits, the `QUARTER` segment is composed of 1 digit, and the `PATCH` segment is also composed of 1 digit. For example: - An implementation based on the version 2023 Q2 of the ACLE with no further patch releases will define `__ARM_ACLE` as `202320`. - An implementation based on a hypothetical version 2024 Q3 of the ACLE with two patch releases will define `__ARM_ACLE` as `202432`. NOTE: Previously, the macro followed the previous versioning scheme and was defined as `100 * major_version + minor_version`, which was the version of this specification implemented. For instance, an implementation implementing version 2.1 of the ACLE specification defined `__ARM_ACLE` as `201`. `__ARM_ACLE_VERSION(year, quarter, patch)` is defined to express a given ACLE version. Returns with the version number in the same format as the `__ARM_ACLE` does. Checking the minimum required ACLE version could be written as: ``` c #if __ARM_ACLE >= __ARM_ACLE_VERSION(2024, 1, 0) ``` ## Endianness `__ARM_BIG_ENDIAN` is defined as 1 if data is stored by default in big-endian format. If the macro is not set, data is stored in little-endian format. (Aside: the "mixed-endian" format for double-precision numbers, used on some very old Arm FPU implementations, is not supported by ACLE or the Arm ABI.) ## Instruction set architecture and features References to the target architecture refer to the target as configured in the tools, for example by appropriate command-line options. This may be a subset or intersection of actual targets, in order to produce a binary that runs on more than one real architecture. For example, use of specific features may be disabled. In the 32-bit architecture, some hardware features may be accessible from only one or other of A32 or T32 state. For example, in the v5TE and v6 architectures, DSP instructions and (where available) VFP instructions, are only accessible in A32 state, while in the v7-R architecture, hardware divide is only accessible from T32 state. Where both states are available, the implementation should set feature test macros indicating that the hardware feature is accessible. To provide access to the hardware feature, an implementation might override the programmer's preference for target instruction set, or generate an interworking call to a helper function. This mechanism is outside the scope of ACLE. In cases where the implementation is given a hard requirement to use only one state (for example to support validation, or post-processing) then it should set feature test macros only for the hardware features available in that state as if compiling for a core where the other instruction set was not present. An implementation that allows a user to indicate which functions go into which state (either as a hard requirement or a preference) is not required to change the settings of architectural feature test macros. ### Arm architecture level `__ARM_ARCH` is defined as an integer value indicating the current Arm instruction set architecture (for example 7 for the Arm v7-A architecture implemented by Cortex-A8 or the Armv7-M architecture implemented by Cortex-M3 or 8 for the Armv8-A architecture implemented by Cortex-A57). Armv8.1-A [[ARMARMv81]](#ARMARMv81) onwards, the value of `__ARM_ARCH` is scaled up to include minor versions. The formula to calculate the value of `__ARM_ARCH` from Armv8.1-A [[ARMARMv81]](#ARMARMv81) onwards is given by the following formula: > For an Arm architecture ArmvX.Y, `__ARM_ARCH` = X * 100 + Y. > For example, for Armv8.1 `__ARM_ARCH` = 801. Since ACLE only supports the Arm architecture, this macro would always be defined in an ACLE implementation. Note that the `__ARM_ARCH` macro is defined even for cores which only support the T32 instruction set. ### Instruction set architecture (A32/T32/A64) `__ARM_ARCH_ISA_ARM` is defined to 1 if the core supports the Arm instruction set. It is not defined for M-profile cores. `__ARM_ARCH_ISA_THUMB` is defined to 1 if the core supports the original T32 instruction set (including the v6-M architecture) and 2 if it supports the T32 instruction set as found in the v6T2 architecture and all v7 architectures. `__ARM_ARCH_ISA_A64` is defined to 1 if the core supports AArch64's A64 instruction set. `__ARM_32BIT_STATE` is defined to 1 if code is being generated for AArch32. `__ARM_64BIT_STATE` is defined to 1 if code is being generated for AArch64. ### Architectural profile (A, R, M or pre-Cortex) `__ARM_ARCH_PROFILE` is defined to be one of the char literals `'A'`, `'R'`, `'M'` or `'S'`, or unset, according to the architectural profile of the target. `'S'` indicates the common subset of the A and R profiles. The common subset of the A, R and M profiles is indicated by ``` c __ARM_ARCH == 7 && !defined (__ARM_ARCH_PROFILE) ``` This macro corresponds to the `Tag_CPU_arch_profile` object build attribute. It may be useful to writers of system code. It is expected in most cases programmers will use more feature-specific tests. The macro is undefined for architectural targets which predate the use of architectural profiles. ### Unaligned access supported in hardware `__ARM_FEATURE_UNALIGNED` is defined if the target supports unaligned access in hardware, at least to the extent of being able to load or store an integer word at any alignment with a single instruction. (There may be restrictions on load-multiple and floating-point accesses.) Note that whether a code generation target permits unaligned access will in general depend on the settings of system register bits, so an implementation should define this macro to match the user's expectations and intentions. For example, a command-line option might be provided to disable the use of unaligned access, in which case this macro would not be defined. ### LDREX/STREX This feature was deprecated in ACLE 2.0. It is strongly recommended that C11/C++11 atomics be used instead. (See also [Synchronization, barrier, and hint intrinsics](#synchronization-barrier-and-hint-intrinsics).) `__ARM_FEATURE_LDREX` is defined if the load/store-exclusive instructions (LDREX/STREX) are supported. Its value is a set of bits indicating available widths of the access, as powers of 2. The following bits are used: | **Bit** | **Value** | **Access width** | **Instruction** | | ------- | --------- | ---------------- | --------------- | | 0 | 0x01 | byte | LDREXB/STREXB | | 1 | 0x02 | halfword | LDREXH/STREXH | | 2 | 0x04 | word | LDREX/STREX | | 3 | 0x08 | doubleword | LDREXD/STREXD | Other bits are reserved. The following values of `__ARM_FEATURE_LDREX` may occur: | **Macro value** | **Access widths** | **Example architecture** | | --------------- | -------------------------------- | ------------------------ | | (undefined) | none | Armv5, Armv6-M | | 0x04 | word | Armv6 | | 0x07 | word, halfword, byte | Armv7-M | | 0x0F | doubleword, word, halfword, byte | Armv6K, Armv7-A/R | Other values are reserved. The LDREX/STREX instructions are introduced in recent versions of the Arm architecture and supersede the SWP instruction. Where both are available, Arm strongly recommends programmers to use LDREX/STREX rather than SWP. Note that platforms may choose to make SWP unavailable in user mode and emulate it through a trap to a platform routine, or fault it. ### CLZ `__ARM_FEATURE_CLZ` is defined to 1 if the CLZ (count leading zeroes) instruction is supported in hardware. Note that ACLE provides the `__clz()` family of intrinsics (see [Miscellaneous data-processing intrinsics](#miscellaneous-data-processing-intrinsics)) even when `__ARM_FEATURE_CLZ` is not defined. ### Q (saturation) flag `__ARM_FEATURE_QBIT` is defined to 1 if the Q (saturation) global flag exists and the intrinsics defined in [The Q (saturation) flag](#the-q-saturation-flag) are available. This flag is used with the DSP saturating-arithmetic instructions (such as QADD) and the width-specified saturating instructions (SSAT and USAT). Note that either of these classes of instructions may exist without the other: for example, v5E has only QADD while v7-M has only SSAT. Intrinsics associated with the Q-bit and their feature macro `__ARM_FEATURE_QBIT` are deprecated in ACLE 2.0 for A-profile. They are fully supported for M-profile and R-profile. This macro is defined for AArch32 only. ### DSP instructions `__ARM_FEATURE_DSP` is defined to 1 if the DSP (v5E) instructions are supported and the intrinsics defined in [Saturating intrinsics](#saturating-intrinsics) are available. These instructions include QADD, SMULBB and others. This feature also implies support for the Q flag. `__ARM_FEATURE_DSP` and its associated intrinsics are deprecated in ACLE 2.0 for A-profile. They are fully supported for M and R-profiles. This macro is defined for AArch32 only. ### Saturation instructions `__ARM_FEATURE_SAT` is defined to 1 if the SSAT and USAT instructions are supported and the intrinsics defined in [Width-specified saturation intrinsics](#width-specified-saturation-intrinsics) are available. This feature also implies support for the Q flag. `__ARM_FEATURE_SAT` and its associated intrinsics are deprecated in ACLE 2.0 for A-profile. They are fully supported for M and R-profiles. This macro is defined for AArch32 only. ### 32-bit SIMD instructions `__ARM_FEATURE_SIMD32` is defined to 1 if the 32-bit SIMD instructions are supported and the intrinsics defined in [32-bit SIMD Operations](#32-bit-simd-operations) are available. This also implies support for the GE global flags which indicate byte-by-byte comparison results. `__ARM_FEATURE_SIMD32` is deprecated in ACLE 2.0 for A-profile. Users are encouraged to use Neon Intrinsics as an equivalent for the 32-bit SIMD intrinsics functionality. However they are fully supported for M and R-profiles. This is defined for AArch32 only. ### Hardware integer divide `__ARM_FEATURE_IDIV` is defined to 1 if the target has hardware support for 32-bit integer division in all available instruction sets. Signed and unsigned versions are both assumed to be available. The intention is to allow programmers to choose alternative algorithm implementations depending on the likely speed of integer division. Some older R-profile targets have hardware divide available in the T32 instruction set only. This can be tested for using the following test: ``` c #if __ARM_FEATURE_IDIV || (__ARM_ARCH_PROFILE == 'R') ``` ### CRC32 extension `__ARM_FEATURE_CRC32` is defined to 1 if the CRC32 instructions are supported and the intrinsics defined in [CRC32 intrinsics](#crc32-intrinsics) are available. These instructions include CRC32B, CRC32H and others. This is only available when `__ARM_ARCH >= 8`. ### Random Number Generation Extension `__ARM_FEATURE_RNG` is defined to 1 if the Random Number Generation instructions are supported and the intrinsics defined in [Random number generation intrinsics](#random-number-generation-intrinsics) are available. ### Branch Target Identification `__ARM_FEATURE_BTI_DEFAULT` is defined to 1 if the Branch Target Identification extension is used to protect branch destinations by default. The protection applied to any particular function may be overridden by mechanisms such as function attributes. `__ARM_FEATURE_BTI` is defined to 1 if Branch Target Identification extension is available on the target. It is undefined otherwise. ### Pointer Authentication `__ARM_FEATURE_PAC_DEFAULT` is defined as a bitmap to indicate the use of the Pointer Authentication extension to protect code against code reuse attacks by default. The bits are defined as follows: | **Bit** | **Meaning** | | ------- | ------------------------------------ | | 0 | Protection using the A key | | 1 | Protection using the B key | | 2 | Protection including leaf functions | | 3 | Protection using PC as a diversifier | For example, a value of `0x5` indicates that the Pointer Authentication extension is used to protect function entry points, including leaf functions, using the A key for signing. The protection applied to any particular function may be overridden by mechanisms such as function attributes. `__ARM_FEATURE_PAUTH` is defined to 1 if Pointer Authentication extension (FEAT_PAuth) is available on the target. It is undefined otherwise. `__ARM_FEATURE_PAUTH_LR` is defined to 1 if Armv9.5-A enhancements to the Pointer Authentication extension (FEAT_PAuth_LR) are available on the target. It is undefined otherwise. ### Large System Extensions `__ARM_FEATURE_ATOMICS` is defined if the Large System Extensions introduced in the Armv8.1-A [[ARMARMv81]](#ARMARMv81) architecture are supported on this target. Note: It is strongly recommended that standardized C11/C++11 atomics are used to implement atomic operations in user code. ### Transactional Memory Extension `__ARM_FEATURE_TME` is defined to `1` if the Transactional Memory Extension instructions are supported in hardware and intrinsics defined in [Transactional Memory Extension (TME) intrinsics](#transactional-memory-extension-tme-intrinsics) are available. ### Armv8.7-A Load/Store 64 Byte extension `__ARM_FEATURE_LS64` is defined to 1 if the Armv8.7-A `LD64B`, `ST64B`, `ST64BV` and `ST64BV0` instructions for atomic 64-byte access to device memory are supported. This macro may only ever be defined in the AArch64 execution state. Intrinsics for using these instructions are specified in [Load/store 64 Byte intrinsics](#loadstore-64-byte-intrinsics). ### memcpy family of memory operations standarization instructions - MOPS If the `CPYF*`, `CPY*`, `SET*` and `SETG*` instructions are supported, `__ARM_FEATURE_MOPS` is defined to 1. These instructions were introduced in the Armv8.8-A and Armv9.3-A architecture updates for standardization of `memcpy`, `memset`, and `memmove` family of memory operations (MOPS). The `__ARM_FEATURE_MOPS` macro can only be implemented in the AArch64 execution state. Intrinsics for the use of these instructions are specified in [memcpy family of operations intrinsics - MOPS](#memcpy-family-of-operations-intrinsics---mops) ### RCPC `__ARM_FEATURE_RCPC` is set if the weaker RCpc (Release Consistent processor consistent) model is supported. It is undefined otherwise. The value indicates the set of Load-Acquire and Store-Release instructions available. The intention is to allow programmers to guard the usage of these instructions in inline assembly. If defined, the value of `__ARM_FEATURE_RCPC` remains consistent with the decimal value of `LRCPC` field (bits [23:20]) in the `ID_AA64ISAR1_EL1` register. For convenience these are shown below: | **Value** | **Feature** | **Instructions** | **Availability** | | --------- | ----------- | ------------------------------- | ------------------------- | | 1 | FEAT_LRCPC | LDAPR* instructions | Armv8.3, optional Armv8.2 | | 2 | FEAT_LRCPC2 | LDAPUR* and STLUR* instructions | Armv8.4, optional Armv8.2 | | 3 | FEAT_LRCPC3 | See FEAT_LRCPC3 documentation | Armv8.9, optional Armv8.2 | The `__ARM_FEATURE_RCPC` macro can only be implemented in the AArch64 execution state. ### 128-bit system registers If the `MRRS` and `MSRR` instructions are supported, `__ARM_FEATURE_SYSREG128` is defined to 1. These instructions were introduced in the Armv9.4-A architecture updates to support 128-bit system register accesses. The `__ARM_FEATURE_SYSREG128` macro can only be implemented in the AArch64 execution state. Intrinsics for the use of these instructions are specified in [Special register intrinsics](#special-register-intrinsics). ## Floating-point and vector hardware ### Hardware floating point `__ARM_FP` is set if hardware floating-point is available. The value is a set of bits indicating the floating-point precisions supported. The following bits are used: | **Bit** | **Value** | **Precision** | | ------- | --------- | ---------------------------- | | 1 | 0x02 | half (16-bit) data type only | | 2 | 0x04 | single (32-bit) | | 3 | 0x08 | double (64-bit) | Bits 0 and 4..31 are reserved Currently, the following values of `__ARM_FP` may occur (assuming the processor configuration option for hardware floating-point support is selected where available): | **Value** | **Precisions** | **Example processor** | | ----------- | -------------------- | ----------------------------------------------------- | | (undefined) | none | any processor without hardware floating-point support | | 0x04 | single | Cortex-R5 when configured with SP only | | 0x06 | single, half | Cortex-M4.fp | | 0x0C | double, single | Arm9, Arm11, Cortex-A8, Cortex-R4 | | 0x0E | double, single, half | Cortex-A9, Cortex-A15, Cortex-R7 | Other values are reserved. Standard C implementations support single and double precision floating-point irrespective of whether floating-point hardware is available. However, an implementation might choose to offer a mode to diagnose or fault use of floating-point arithmetic at a precision not supported in hardware. Support for 16-bit floating-point language or 16-bit brain floating-point language extensions (see [Half-precision (16-bit) floating-point format](#half-precision-16-bit-floating-point-format) and [Brain 16-bit floating-point support](#brain-16-bit-floating-point-support)) is only required if supported in hardware. ### Half-precision (16-bit) floating-point format `__ARM_FP16_FORMAT_IEEE` is defined to 1 if the IEEE 754-2008 [[IEEE-FP]](#IEEE-FP) 16-bit floating-point format is used. `__ARM_FP16_FORMAT_ALTERNATIVE` is defined to 1 if the Arm alternative [[ARMARM]](#ARMARM) 16-bit floating-point format is used. This format removes support for infinities and NaNs in order to provide an additional binade. At most one of these macros will be defined. See [Half-precision floating-point](#half-precision-floating-point) for details of half-precision floating-point types. ### Half-precision argument and result `__ARM_FP16_ARGS` is defined to 1 if `__fp16` can be used as an argument and result. ### Vector extensions #### Advanced SIMD architecture extension (Neon) `__ARM_NEON` is defined to a value indicating the Advanced SIMD (Neon) architecture supported. The only current value is 1. In principle, for AArch32, the Neon architecture can exist in an integer-only version. To test for the presence of Neon floating-point vector instructions, test `__ARM_NEON_FP`. When Neon does occur in an integer-only version, the VFP scalar instruction set is also not present. See [[ARMARM]](#ARMARM) (table A2-4) for architecturally permitted combinations. `__ARM_NEON` is always set to 1 for AArch64. #### Neon floating-point `__ARM_NEON_FP` is defined as a bitmap to indicate floating-point support in the Neon architecture. The meaning of the values is the same as for `__ARM_FP`. This macro is undefined when the Neon extension is not present or does not support floating-point. Current AArch32 Neon implementations do not support double-precision floating-point even when it is present in VFP. 16-bit floating-point format is supported in Neon if and only if it is supported in VFP. Consequently, the definition of `__ARM_NEON_FP` is the same as `__ARM_FP` except that the bit to indicate double-precision is not set for AArch32. Double-precision is always set for AArch64. If `__ARM_FEATURE_FMA` and `__ARM_NEON_FP` are both defined, fused-multiply instructions are available in Neon also. #### Scalable Vector Extension (SVE) `__ARM_FEATURE_SVE` is defined to 1 if there is hardware support for the FEAT_SVE instructions and if the associated [ACLE features](#sve-language-extensions-and-intrinsics) are available. This implies that `__ARM_NEON` and `__ARM_NEON_FP` are both nonzero. The following macros indicate the presence of various optional SVE language extensions: **`__ARM_FEATURE_SVE_BITS==N`** > When N is nonzero, this indicates that the implementation is generating > code for an N-bit SVE target and that the implementation supports the > `arm_sve_vector_bits(N)` attribute. N may also be zero, but this carries > the same meaning as not defining the macro. See > [The __ARM_FEATURE_SVE_BITS macro](#the-__arm_feature_sve_bits-macro) > for details. **`__ARM_FEATURE_SVE_VECTOR_OPERATORS==N`** > `N >= 1` indicates that applying the `arm_sve_vector_bits` attribute > to an SVE vector type creates a type that supports the GNU vector > extensions. This condition is only meaningful when > `__ARM_FEATURE_SVE_BITS` is nonzero. See [`arm_sve_vector_bits` behavior > specific to vectors](#arm_sve_vector_bits-behavior-specific-to-vectors) > for details. > `N >= 2` indicates that the operators outlined in the GNU vector > extensions additionally work on sizeless SVE vector types like `svint32_t`. > The availability of operators on sizeless types is independent of > `__ARM_FEATURE_SVE_BITS`. **`__ARM_FEATURE_SVE_PREDICATE_OPERATORS==N`** > `N >= 1` indicates that applying the `arm_sve_vector_bits` attribute to > `svbool_t` creates a type that supports basic built-in vector operations. > The state of this macro is only meaningful when `__ARM_FEATURE_SVE_BITS` > is nonzero. See [`arm_sve_vector_bits` behavior specific to > predicates](#arm_sve_vector_bits-behavior-specific-to-predicates) > for details. > `N >= 2` indicates that the built-in vector operations described above > additionally work on `svbool_t`. > The availability of operators on `svbool_t` is independent of > `__ARM_FEATURE_SVE_BITS`. #### SVE2 `__ARM_FEATURE_SVE2` is defined to 1 if there is hardware support for the Armv9-A SVE2 extension (FEAT_SVE2) and if the associated ACLE intrinsics are available. This implies that `__ARM_FEATURE_SVE` is nonzero. `__ARM_FEATURE_SVE2p1` is defined to 1 if the FEAT_SVE2p1 instructions are available and if the associated [ACLE features] (#sme-language-extensions-and-intrinsics) are supported. #### NEON-SVE Bridge macros `__ARM_NEON_SVE_BRIDGE` is defined to 1 if [NEON-SVE Bridge](#neon-sve-bridge) intrinsics are available. This implies that the following macros are nonzero: * `__ARM_NEON` * `__ARM_NEON_FP` * `__ARM_FEATURE_SVE` #### Scalable Matrix Extension (SME) The specification for SME is in [**Beta** state](#current-status-and-anticipated-changes) and may change or be extended in the future. `__ARM_FEATURE_SME` is defined to 1 if there is hardware support for the FEAT_SME instructions and if the associated [ACLE features](#sme-language-extensions-and-intrinsics) are available. This implies that `__ARM_FEATURE_SVE` is nonzero. In addition, `__ARM_FEATURE_LOCALLY_STREAMING` is defined to 1 if the [`arm_locally_streaming`](#arm_locally_streaming) attribute is available. `__ARM_FEATURE_SME2` is defined to 1 if the FEAT_SME2 instructions are available and if the associated [ACLE features](#sme-language-extensions-and-intrinsics) are supported. #### M-profile Vector Extension `__ARM_FEATURE_MVE` is defined as a bitmap to indicate M-profile Vector Extension (MVE) support. | **Bit** | **Value** | **Support** | | ------- | --------- | ------------------ | | 0 | 0x01 | Integer MVE | | 1 | 0x02 | Floating-point MVE | #### Wireless MMX If Wireless MMX operations are available on the target, `__ARM_WMMX` is defined to a value that indicates the level of support, corresponding to the `Tag_WMMX_arch` build attribute. This specification does not further define source-language features to support Wireless MMX. ### 16-bit floating-point extensions #### 16-bit floating-point data processing operations `__ARM_FEATURE_FP16_SCALAR_ARITHMETIC` is defined to `1` if the 16-bit floating-point arithmetic instructions are supported in hardware and the associated scalar intrinsics defined by ACLE are available. Note that this implies: * `__ARM_FP16_FORMAT_IEEE == 1` * `__ARM_FP16_FORMAT_ALTERNATIVE == 0` * `__ARM_FP & 0x02 == 1` `__ARM_FEATURE_FP16_VECTOR_ARITHMETIC` is defined to `1` if the 16-bit floating-point arithmetic instructions are supported in hardware and the associated vector intrinsics defined by ACLE are available. Note that this implies: * `__ARM_FP16_FORMAT_IEEE == 1` * `__ARM_FP16_FORMAT_ALTERNATIVE == 0` * `__ARM_FP & 0x02 == 1` * `__ARM_NEON_FP & 0x02 == 1` #### FP16 FML extension `__ARM_FEATURE_FP16_FML` is defined to 1 if the FP16 multiplication variant instructions from Armv8.2-A are supported and intrinsics targeting them are available. This implies that `__ARM_FEATURE_FP16_SCALAR_ARITHMETIC` is defined to a nonzero value. #### Brain 16-bit floating-point support `__ARM_BF16_FORMAT_ALTERNATIVE` is defined to 1 if the Arm alternative [[ARMARM]](#ARMARM) 16-bit brain floating-point format is used. This format closely resembles the IEEE 754 single-precision format. As such a brain half-precision floating point value can be converted to an IEEE 754 single-floating point format by appending 16 zero bits at the end. `__ARM_FEATURE_BF16_VECTOR_ARITHMETIC` is defined to `1` if there is hardware support for the Advanced SIMD brain 16-bit floating-point arithmetic instructions and if the associated ACLE vector intrinsics are available. This implies: * `__ARM_FP & 0x02 == 1` * `__ARM_NEON_FP & 0x02 == 1` Similarly, `__ARM_FEATURE_SVE_BF16` is defined to `1` if there is hardware support for the SVE BF16 extensions and if the associated ACLE intrinsics are available. This implies that `__ARM_FEATURE_BF16_VECTOR_ARITHMETIC` and `__ARM_FEATURE_SVE` are both nonzero. See [Half-precision brain floating-point](#half-precision-brain-floating-point) for details of half-precision brain floating-point types. ### Cryptographic extensions #### “Crypto” extension NOTE: The `__ARM_FEATURE_CRYPTO` macro is deprecated in favor of the finer grained feature macros described below. `__ARM_FEATURE_CRYPTO` is defined to 1 if the Armv8-A Crypto instructions are supported and intrinsics targeting them are available. These instructions include AES{E, D}, SHA1{C, P, M} and others. This also implies `__ARM_FEATURE_AES` and `__ARM_FEATURE_SHA2`. #### AES extension `__ARM_FEATURE_AES` is defined to 1 if there is hardware support for the Advanced SIMD AES Crypto instructions from Armv8-A and if the associated ACLE intrinsics are available. These instructions are identified by `FEAT_AES` and `FEAT_PMULL` in [[ARMARMv8]](#ARMARMv8), and they include AES{E, D}, AESMC, AESIMC and others. In addition, `__ARM_FEATURE_SVE2_AES` is defined to `1` if there is hardware support for the SVE2 AES (FEAT_SVE_AES) instructions and if the associated ACLE intrinsics are available. This implies that `__ARM_FEATURE_AES` and `__ARM_FEATURE_SVE2` are both nonzero. #### SHA2 extension `__ARM_FEATURE_SHA2` is defined to 1 if the SHA1 & SHA2-256 Crypto instructions from Armv8-A are supported and intrinsics targeting them are available. These instructions are identified by `FEAT_SHA1` and `FEAT_SHA256` in [[ARMARMv8]](#ARMARMv8), and they include SHA1{C, P, M}, SHA256H, SHA256H2... and others. #### SHA512 extension `__ARM_FEATURE_SHA512` is defined to 1 if the SHA2-512 Crypto instructions from Armv8.2-A are supported and intrinsics targeting them are available. These instructions are identified by `FEAT_SHA512` in [[ARMARMv82]](#ARMARMv82), and they include SHA1{C, P, M}, SHA256H, SHA256H2, ..., SHA512H, SHA512H2, SHA512SU0... and others. Note: `FEAT_SHA512` requires both `FEAT_SHA1` and `FEAT_SHA256`. #### SHA3 extension `__ARM_FEATURE_SHA3` is defined to 1 if there is hardware support for the Advanced SIMD SHA1 & SHA2 Crypto instructions from Armv8-A and the SHA2 and SHA3 instructions from Armv8.2-A and newer and if the associated ACLE intrinsics are available. These instructions include AES{E, D}, SHA1{C, P, M}, RAX, and others. In addition, `__ARM_FEATURE_SVE2_SHA3` is defined to `1` if there is hardware support for the SVE2 SHA3 (FEAT_SVE_SHA3) instructions and if the associated ACLE intrinsics are available. This implies that `__ARM_FEATURE_SHA3` and `__ARM_FEATURE_SVE2` are both nonzero. #### SM3 extension `__ARM_FEATURE_SM3` is defined to 1 if there is hardware support for Advanced SIMD SM3 Crypto instructions from Armv8.2-A and if the associated ACLE intrinsics are available. These instructions include SM3{TT1A, TT1B}, and others. In addition, `__ARM_FEATURE_SVE2_SM3` is defined to `1` if there is hardware support for the SVE2 SM3 (FEAT_SVE_SM3) instructions and if the associated ACLE intrinsics are available. This implies that `__ARM_FEATURE_SM3` and `__ARM_FEATURE_SVE2` are both nonzero. #### SM4 extension `__ARM_FEATURE_SM4` is defined to 1 if there is hardware support for the Advanced SIMD SM4 Crypto instructions from Armv8.2-A and if the associated ACLE intrinsics are available. These instructions include SM4{E, EKEY} and others. In addition, `__ARM_FEATURE_SVE2_SM4` is defined to `1` if there is hardware support for the SVE2 SM4 (FEAT_SVE_SM4) instructions and if the associated ACLE intrinsics are available. This implies that `__ARM_FEATURE_SM4` and `__ARM_FEATURE_SVE2` are both nonzero. ### Other floating-point and vector extensions #### Fused multiply-accumulate (FMA) `__ARM_FEATURE_FMA` is defined to 1 if the hardware floating-point architecture supports fused floating-point multiply-accumulate, i.e. without intermediate rounding. Note that C implementations are encouraged [[C99]](#C99) (7.12) to ensure that defines `FP_FAST_FMAF` or `FP_FAST_FMA`, which can be tested by portable C code. A C implementation on Arm might define these macros by testing `__ARM_FEATURE_FMA` and `__ARM_FP`. This macro implies support for floating-point instructions but it does not in itself imply support for vector instructions. See [Neon floating-point](#neon-floating-point) for the conditions under which vector fused multiply-accumulate operations are available. #### Directed rounding `__ARM_FEATURE_DIRECTED_ROUNDING` is defined to 1 if the directed rounding and conversion vector instructions are supported and rounding and conversion intrinsics are available. This is only available when `__ARM_ARCH >= 8`. #### Armv8.5-A Floating-point rounding extension `__ARM_FEATURE_FRINT` is defined to 1 if the Armv8.5-A rounding number instructions are supported and the scalar and vector intrinsics are available. This macro may only ever be defined in the AArch64 execution state. The scalar intrinsics are specified in [Floating-point data-processing intrinsics](#floating-point-data-processing-intrinsics) and are not expected to be for general use. They are defined for uses that require the specialist rounding behavior of the relevant instructions. The vector intrinsics are specified in the Arm Neon Intrinsics Reference Architecture Specification [[Neon]](#Neon). #### Javascript floating-point conversion `__ARM_FEATURE_JCVT` is defined to 1 if the FJCVTZS (AArch64) or VJCVT (AArch32) instruction and the [associated intrinsic](#floating-point-data-processing-intrinsics) are available. #### Numeric maximum and minimum `__ARM_FEATURE_NUMERIC_MAXMIN` is defined to 1 if the IEEE 754-2008 compliant floating point maximum and minimum vector instructions are supported and intrinsics targeting these instructions are available. This is only available when `__ARM_ARCH >= 8`. #### Rounding doubling multiplies `__ARM_FEATURE_QRDMX` is defined to 1 if SQRDMLAH and SQRDMLSH instructions and their associated intrinsics are available. #### Dot Product extension `__ARM_FEATURE_DOTPROD` is defined if the dot product data manipulation instructions are supported and the vector intrinsics are available. Note that this implies: * `__ARM_NEON == 1` #### Complex number intrinsics `__ARM_FEATURE_COMPLEX` is defined if the complex addition and complex multiply-accumulate vector instructions are supported. Note that this implies: * `__ARM_NEON == 1` These instructions require that the input vectors are organized such that the real and imaginary parts of the complex number are stored in alternating sequences: real, imag, real, imag, ... etc. #### Matrix Multiply Intrinsics ##### Multiplication of 8-bit integer matrices `__ARM_FEATURE_MATMUL_INT8` is defined to `1` if there is hardware support for the Advanced SIMD integer matrix multiply instructions are if the associated ACLE intrinsics are available. This implies that `__ARM_NEON` is nonzero. In addition, `__ARM_FEATURE_SVE_MATMUL_INT8` is defined to `1` if there is hardware support for the SVE forms of these instructions and if the associated ACLE intrinsics are available. This implies that `__ARM_FEATURE_MATMUL_INT8` and `__ARM_FEATURE_SVE` are both nonzero. ##### Multiplication of 32-bit floating-point matrices `__ARM_FEATURE_SVE_MATMUL_FP32` is defined to `1` if there is hardware support for the SVE 32-bit floating-point matrix multiply (FEAT_F32MM) instructions and if the associated ACLE intrinsics are available. This implies that `__ARM_FEATURE_SVE` is nonzero. ##### Multiplication of 64-bit floating-point matrices `__ARM_FEATURE_SVE_MATMUL_FP64` is defined to `1` if there is hardware support for the SVE 64-bit floating-point matrix multiply (FEAT_F64MM) instructions and if the associated ACLE intrinsics are available. This implies that `__ARM_FEATURE_SVE` is nonzero. #### Bit permute extension `__ARM_FEATURE_SVE2_BITPERM` is defined to 1 if there is hardware support for the SVE2 bit permute (FEAT_SVE_BitPerm) instructions and if the associated ACLE intrinsics are available. This implies that `__ARM_FEATURE_SVE2` is nonzero. #### 16-bit to 64-bit integer widening outer product intrinsics The specification for SME is in [**Beta** state](#current-status-and-anticipated-changes) and may change or be extended in the future. `__ARM_FEATURE_SME_I16I64` is defined to `1` if there is hardware support for the SME 16-bit to 64-bit integer widening outer product (FEAT_SME_I16I64) instructions and if their associated intrinsics are available. This implies that `__ARM_FEATURE_SME` is nonzero. #### Double precision floating-point outer product intrinsics The specification for SME is in [**Beta** state](#current-status-and-anticipated-changes) and may change or be extended in the future. `__ARM_FEATURE_SME_F64F64` is defined to `1` if there is hardware support for the SME double precision floating-point outer product (FEAT_SME_F64F64) instructions and if their associated intrinsics are available. This implies that `__ARM_FEATURE_SME` is nonzero. ## Floating-point model These macros test the floating-point model implemented by the compiler and libraries. The model determines the guarantees on arithmetic and exceptions. `__ARM_FP_FAST` is defined to 1 if floating-point optimizations may occur such that the computed results are different from those prescribed by the order of operations according to the C standard. Examples of such optimizations would be reassociation of expressions to reduce depth, and replacement of a division by constant with multiplication by its reciprocal. `__ARM_FP_FENV_ROUNDING` is defined to 1 if the implementation allows the rounding to be configured at runtime using the standard C fesetround() function and will apply this rounding to future floating-point operations. The rounding mode applies to both scalar floating-point and Neon. The floating-point implementation might or might not support denormal values. If denormal values are not supported then they are flushed to zero. Implementations may also define the following macros in appropriate floating-point modes: `__STDC_IEC_559__` is defined if the implementation conforms to IEC This implies support for floating-point exception status flags, including the inexact exception. This macro is specified by [[C99]](#C99) (6.10.8). `__SUPPORT_SNAN__` is defined if the implementation supports signalling NaNs. This macro is specified by the C standards proposal WG14 N965 Optional support for Signaling NaNs. (Note: this was not adopted into C11.) ## Procedure call standard `__ARM_PCS` is defined to 1 if the default procedure calling standard for the translation unit conforms to the base PCS defined in [[AAPCS]](#AAPCS). This is supported on AArch32 only. `__ARM_PCS_VFP` is defined to 1 if the default is to pass floating-point parameters in hardware floating-point registers using the VFP variant PCS defined in [[AAPCS]](#AAPCS). This is supported on AArch32 only. `__ARM_PCS_AAPCS64` is defined to 1 if the default procedure calling standard for the translation unit conforms to the [[AAPCS64]](#AAPCS64). Note that this should reflect the implementation default for the translation unit. Implementations which allow the PCS to be set for a function, class or namespace are not expected to redefine the macro within that scope. ## Position-independent code `__ARM_ROPI` is defined to 1 if the translation unit is being compiled in read-only position independent mode. In this mode, all read-only data and functions are at a link-time constant offset from the program counter. `__ARM_RWPI` is defined to 1 if the translation unit is being compiled in read-write position independent mode. In this mode, all writable data is at a link-time constant offset from the static base register defined in [[AAPCS]](#AAPCS). The ROPI and RWPI position independence modes are compatible with each other, so the `__ARM_ROPI` and `__ARM_RWPI` macros may be defined at the same time. ## Coprocessor intrinsics `__ARM_FEATURE_COPROC` is defined as a bitmap to indicate the presence of coprocessor intrinsics for the target architecture. If `__ARM_FEATURE_COPROC` is undefined or zero, that means there is no support for coprocessor intrinsics on the target architecture. The following bits are used: | **Bit** | **Value** | **Intrinsics Available** | | ------- | --------- | --------------------------------------------------------------------------------------- | | 0 | 0x1 | __arm_cdp __arm_ldc, __arm_ldcl, __arm_stc, __arm_stcl, __arm_mcr and __arm_mrc | | 1 | 0x2 | __arm_cdp2, __arm_ldc2, __arm_stc2, __arm_ldc2l, __arm_stc2l, __arm_mcr2 and __arm_mrc2 | | 2 | 0x4 | __arm_mcrr and __arm_mrrc | | 3 | 0x8 | __arm_mcrr2 and __arm_mrrc2 | ## Custom Datapath Extension `__ARM_FEATURE_CDE` is defined to 1 if the Arm Custom Datapath Extension (CDE) is supported. `__ARM_FEATURE_CDE_COPROC` is a bitmap indicating the CDE coprocessors available. The following bits are used: | **Bit** | **Value** | **CDE Coprocessor available** | | ------- | --------- | --------------------------------- | | 0 | 0x01 | `p0` | | 1 | 0x02 | `p1` | | 2 | 0x04 | `p2` | | 3 | 0x08 | `p3` | | 4 | 0x10 | `p4` | | 5 | 0x20 | `p5` | | 6 | 0x40 | `p6` | | 7 | 0x80 | `p7` | ## Mapping of object build attributes to predefines This section is provided for guidance. Details of build attributes can be found in [[BA]](#BA). | **Tag no.** | **Tag** | **Predefined macro** | | ------------------------ | ---------------------------- | --------------------------------- | | 6 | `Tag_CPU_arch` | `__ARM_ARCH`, `__ARM_FEATURE_DSP` | | 7 | `Tag_CPU_arch_profile` | `__ARM_PROFILE` | | 8 | `Tag_ARM_ISA_use` | `__ARM_ISA_ARM` | | 9 | `Tag_THUMB_ISA_use` | `__ARM_ISA_THUMB` | | 11 | `Tag_WMMX_arch` | `__ARM_WMMX` | | 18 | `Tag_ABI_PCS_wchar_t` | `__ARM_SIZEOF_WCHAR_T` | | 20 | `Tag_ABI_FP_denormal` | | | 21 | `Tag_ABI_FP_exceptions` | | | 22 | `Tag_ABI_FP_user_exceptions` | | | 23 | `Tag_ABI_FP_number_model` | | | 26 | `Tag_ABI_enum_size` | `__ARM_SIZEOF_MINIMAL_ENUM` | | 34 | `Tag_CPU_unaligned_access` | `__ARM_FEATURE_UNALIGNED` | | 36 | `Tag_FP_HP_extension` | `__ARM_FP16_FORMAT_IEEE` | | | | `__ARM_FP16_FORMAT_ALTERNATIVE` | | 38 | `Tag_ABI_FP_16bit_for` | `__ARM_FP16_FORMAT_IEEE` | | | | `__ARM_FP16_FORMAT_ALTERNATIVE` | ## Summary of predefined macros | **Macro name** | **Meaning** | **Example** | |---------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------|-------------| | [`__ARM_32BIT_STATE`](#instruction-set-architecture-a32t32a64) | Code is for AArch32 state | 1 | | [`__ARM_64BIT_STATE`](#instruction-set-architecture-a32t32a64) | Code is for AArch64 state | 1 | | [`__ARM_ACLE`](#testing-for-arm-c-language-extensions) | Indicates ACLE implemented | 101 | | [`__ARM_ALIGN_MAX_PWR`](#alignment-of-static-objects) | Log of maximum alignment of static object | 20 | | [`__ARM_ALIGN_MAX_STACK_PWR`](#alignment-of-stack-objects) | Log of maximum alignment of stack object | 3 | | [`__ARM_ARCH`](#arm-architecture-level) | Arm architecture level | 7 | | [`__ARM_ARCH_ISA_A64`](#instruction-set-architecture-a32t32a64) | AArch64 ISA present | 1 | | [`__ARM_ARCH_ISA_ARM`](#instruction-set-architecture-a32t32a64) | Arm instruction set present | 1 | | [`__ARM_ARCH_ISA_THUMB`](#instruction-set-architecture-a32t32a64) | T32 instruction set present | 2 | | [`__ARM_ARCH_PROFILE`](#architectural-profile-a-r-m-or-pre-cortex) | Architecture profile | `'A'` | | [`__ARM_BF16_FORMAT_ALTERNATIVE`](#brain-16-bit-floating-point-support) | 16-bit brain floating-point, alternative format | 1 | | [`__ARM_BIG_ENDIAN`](#endianness) | Memory is big-endian | 1 | | [`__ARM_FEATURE_AES`](#aes-extension) | AES Crypto extension (Arm v8-A) | 1 | | [`__ARM_FEATURE_ATOMICS`](#large-system-extensions) | Large System Extensions | 1 | | [`__ARM_FEATURE_BF16`](#brain-16-bit-floating-point-support) | 16-bit brain floating-point, vector instruction | 1 | | [`__ARM_FEATURE_BTI_DEFAULT`](#branch-target-identification) | Branch Target Identification | 1 | | [`__ARM_FEATURE_CDE`](#custom-datapath-extension) | Custom Datapath Extension | 0x01 | | [`__ARM_FEATURE_CDE_COPROC`](#custom-datapath-extension) | Custom Datapath Extension | 0xf | | [`__ARM_FEATURE_CLZ`](#clz) | CLZ instruction | 1 | | [`__ARM_FEATURE_COMPLEX`](#complex-number-intrinsics) | Armv8.3-A extension | 1 | | [`__ARM_FEATURE_COPROC`](#coprocessor-intrinsics) | Coprocessor Intrinsics | 1 | | [`__ARM_FEATURE_CRC32`](#crc32-extension) | CRC32 extension | 1 | | [`__ARM_FEATURE_CRYPTO`](#crypto-extension) | Crypto extension | 1 | | [`__ARM_FEATURE_DIRECTED_ROUNDING`](#directed-rounding) | Directed Rounding | 1 | | [`__ARM_FEATURE_DOTPROD`](#availability-of-dot-product-intrinsics) | Dot product extension (ARM v8.2-A) | 1 | | [`__ARM_FEATURE_DSP`](#dsp-instructions) | DSP instructions (Arm v5E) (32-bit-only) | 1 | | [`__ARM_FEATURE_FMA`](#fused-multiply-accumulate-fma) | Floating-point fused multiply-accumulate | 1 | | [`__ARM_FEATURE_FP16_FML`](#fp16-fml-extension) | FP16 FML extension (Arm v8.4-A, optional Armv8.2-A, Armv8.3-A) | 1 | | [`__ARM_FEATURE_FRINT`](#availability-of-armv8.5-a-floating-point-rounding-intrinsics) | Floating-point rounding extension (Arm v8.5-A) | 1 | | [`__ARM_FEATURE_IDIV`](#hardware-integer-divide) | Hardware Integer Divide | 1 | | [`__ARM_FEATURE_JCVT`](#javascript-floating-point-conversion) | Javascript conversion (ARMv8.3-A) | 1 | | [`__ARM_FEATURE_LDREX`](#ldrexstrex) *(Deprecated)* | Load/store exclusive instructions | 0x0F | | [`__ARM_FEATURE_MATMUL_INT8`](#availability-of-armv8.6-a-integer-matrix-multiply-intrinsics) | Integer Matrix Multiply extension (Armv8.6-A, optional Armv8.2-A, Armv8.3-A, Armv8.4-A, Armv8.5-A) | 1 | | [`__ARM_FEATURE_MEMORY_TAGGING`](#memory-tagging) | Memory Tagging (Armv8.5-A) | 1 | | [`__ARM_FEATURE_MOPS`](#memcpy-family-of-memory-operations-standarization-instructions---mops) | `memcpy`, `memset`, and `memmove` family of operations standardization instructions | 1 | | [`__ARM_FEATURE_MVE`](#m-profile-vector-extension) | M-profile Vector Extension | 1 | | [`__ARM_FEATURE_NUMERIC_MAXMIN`](#numeric-maximum-and-minimum) | Numeric Maximum and Minimum | 1 | | [`__ARM_FEATURE_PAC_DEFAULT`](#pointer-authentication) | Pointer authentication protection | 0x5 | | [`__ARM_FEATURE_PAUTH`](#pointer-authentication) | Pointer Authentication Extension (FEAT_PAuth) | 1 | | [`__ARM_FEATURE_PAUTH_LR`](#pointer-authentication) | Armv9.5-A Enhancements to Pointer Authentication Extension (FEAT_PAuth_LR) | 1 | | [`__ARM_FEATURE_QBIT`](#q-saturation-flag) | Q (saturation) flag (32-bit-only) | 1 | | [`__ARM_FEATURE_QRDMX`](#rounding-doubling-multiplies) | SQRDMLxH instructions and associated intrinsics availability | 1 | | [`__ARM_FEATURE_RCPC`](#rcpc) | Release Consistent processor consistent Model (64-bit-only) | 1 | | [`__ARM_FEATURE_RNG`](#random-number-generation-extension) | Random Number Generation Extension (Armv8.5-A) | 1 | | [`__ARM_FEATURE_SAT`](#saturation-instructions) | Width-specified saturation instructions (32-bit-only) | 1 | | [`__ARM_FEATURE_SHA2`](#sha2-extension) | SHA2 Crypto extension (Arm v8-A) | 1 | | [`__ARM_FEATURE_SHA3`](#sha3-extension) | SHA3 Crypto extension (Arm v8.4-A) | 1 | | [`__ARM_FEATURE_SHA512`](#sha512-extension) | SHA2 Crypto ext. (Arm v8.4-A, optional Armv8.2-A, Armv8.3-A) | 1 | | [`__ARM_FEATURE_SIMD32`](#32-bit-simd-instructions) | 32-bit SIMD instructions (Armv6) (32-bit-only) | 1 | | [`__ARM_FEATURE_SM3`](#sm3-extension) | SM3 Crypto extension (Arm v8.4-A, optional Armv8.2-A, Armv8.3-A) | 1 | | [`__ARM_FEATURE_SM4`](#sm4-extension) | SM4 Crypto extension (Arm v8.4-A, optional Armv8.2-A, Armv8.3-A) | 1 | | [`__ARM_FEATURE_SME`](#scalable-matrix-extension-sme) | Scalable Matrix Extension (FEAT_SME) | 1 | | [`__ARM_FEATURE_SME2`](#scalable-matrix-extension-sme) | Scalable Matrix Extension (FEAT_SME2) | 1 | | [`__ARM_FEATURE_SME_F64F64`](#double-precision-floating-point-outer-product-intrinsics) | Double precision floating-point outer product intrinsics (FEAT_SME_F64F64) | 1 | | [`__ARM_FEATURE_SME_I16I64`](#16-bit-to-64-bit-integer-widening-outer-product-intrinsics) | 16-bit to 64-bit integer widening outer product intrinsics (FEAT_SME_I16I64) | 1 | | [`__ARM_FEATURE_SME_LOCALLY_STREAMING`](#scalable-matrix-extension-sme) | Support for the `arm_locally_streaming` attribute | 1 | | [`__ARM_FEATURE_SVE`](#scalable-vector-extension-sve) | Scalable Vector Extension (FEAT_SVE) | 1 | | [`__ARM_FEATURE_SVE_BF16`](#brain-16-bit-floating-point-support) | SVE support for the 16-bit brain floating-point extension (FEAT_BF16) | 1 | | [`__ARM_FEATURE_SVE_BITS`](#scalable-vector-extension-sve) | The number of bits in an SVE vector, when known in advance | 256 | | [`__ARM_FEATURE_SVE_MATMUL_FP32`](#multiplication-of-32-bit-floating-point-matrices) | 32-bit floating-point matrix multiply extension (FEAT_F32MM) | 1 | | [`__ARM_FEATURE_SVE_MATMUL_FP64`](#multiplication-of-64-bit-floating-point-matrices) | 64-bit floating-point matrix multiply extension (FEAT_F64MM) | 1 | | [`__ARM_FEATURE_SVE_MATMUL_INT8`](#multiplication-of-8-bit-integer-matrices) | SVE support for the integer matrix multiply extension (FEAT_I8MM) | 1 | | [`__ARM_FEATURE_SVE_PREDICATE_OPERATORS`](#scalable-vector-extension-sve) | Level of support for C and C++ operators on SVE vector types | 1 | | [`__ARM_FEATURE_SVE_VECTOR_OPERATORS`](#scalable-vector-extension-sve) | Level of support for C and C++ operators on SVE predicate types | 1 | | [`__ARM_FEATURE_SVE2`](#sve2) | SVE version 2 (FEAT_SVE2) | 1 | | [`__ARM_FEATURE_SVE2_AES`](#aes-extension) | SVE2 support for the AES cryptographic extension (FEAT_SVE_AES) | 1 | | [`__ARM_FEATURE_SVE2_BITPERM`](#bit-permute-extension) | SVE2 bit permute extension (FEAT_SVE2_BitPerm) | 1 | | [`__ARM_FEATURE_SVE2_SHA3`](#sha3-extension) | SVE2 support for the SHA3 cryptographic extension (FEAT_SVE_SHA3) | 1 | | [`__ARM_FEATURE_SVE2_SM3`](#sm3-extension) | SVE2 support for the SM3 cryptographic extension (FEAT_SVE_SM3) | 1 | | [`__ARM_FEATURE_SVE2_SM4`](#sm4-extension) | SVE2 support for the SM4 cryptographic extension (FEAT_SVE_SM4) | 1 | | [`__ARM_FEATURE_SVE2p1`](#sve2) | SVE version 2.1 (FEAT_SVE2p1) | [`__ARM_FEATURE_SYSREG128`](#bit-system-registers) | Support for 128-bit system registers (FEAT_SYSREG128) | 1 | | [`__ARM_FEATURE_UNALIGNED`](#unaligned-access-supported-in-hardware) | Hardware support for unaligned access | 1 | | [`__ARM_FP`](#hardware-floating-point) | Hardware floating-point | 1 | | [`__ARM_FP16_ARGS`](#half-precision-argument-and-result) | `__fp16` argument and result | 0x0C | | [`__ARM_FP16_FORMAT_ALTERNATIVE`](#half-precision-16-bit-floating-point-format) | 16-bit floating-point, alternative format | 1 | | [`__ARM_FP16_FORMAT_IEEE`](#half-precision-16-bit-floating-point-format) | 16-bit floating-point, IEEE format | 1 | | [`__ARM_FP_FAST`](#floating-point-model) | Accuracy-losing optimizations | 1 | | [`__ARM_FP_FENV_ROUNDING`](#floating-point-model) | Rounding is configurable at runtime | 1 | | [`__ARM_NEON`](#advanced-simd-architecture-extension-neon) | Advanced SIMD (Neon) extension | 1 | | [`__ARM_NEON_FP`](#neon-floating-point) | Advanced SIMD (Neon) floating-point | 0x04 | | [`__ARM_NEON_SVE_BRIDGE`](#neon-sve-bridge-macros) | Moving data between Neon and SVE data types | 1 | | [`__ARM_PCS`](#procedure-call-standard) | Arm procedure call standard (32-bit-only) | 0x01 | | [`__ARM_PCS_AAPCS64`](#procedure-call-standard) | Arm PCS for AArch64. | 1 | | [`__ARM_PCS_VFP`](#procedure-call-standard) | Arm PCS hardware FP variant in use (32-bit-only) | 1 | | [`__ARM_ROPI`](#position-independent-code) | Read-only PIC in use | 1 | | [`__ARM_RWPI`](#position-independent-code) | Read-write PIC in use | 1 | | [`__ARM_SIZEOF_MINIMAL_ENUM`](#implementation-defined-type-properties) | Size of minimal enumeration type: 1 or 4 | 1 | | [`__ARM_SIZEOF_WCHAR_T`](#implementation-defined-type-properties) | Size of `wchar_t`: 2 or 4 | 2 | | [`__ARM_WMMX`](#wireless-mmx) | Wireless MMX extension (32-bit-only) | 1 | # Attributes and pragmas ## Attribute syntax This section describes ACLE features that use GNU-style attributes. The general rules for attribute syntax are described in the GCC documentation . Briefly, for this declaration: ``` c A int B x C, D y E; ``` attribute `A` applies to both `x` and `y`; `B` and `C` apply to `x` only, and `D` and `E` apply to `y` only. Programmers are recommended to keep declarations simple if attributes are used. Unless otherwise stated, all attribute arguments must be compile-time constants. In addition to the GNU-style attributes described in this section, ACLE also uses [keyword attributes](#keyword-attributes). ## Hardware/software floating-point calling convention The AArch32 PCS defines a base standard, as well as several variants. On targets with hardware FP the AAPCS provides for procedure calls to use either integer or floating-point argument and result registers. ACLE allows this to be selectable per function. ``` c __attribute__((pcs("aapcs"))) ``` applied to a function, selects software (integer) FP calling convention. ``` c __attribute__((pcs("aapcs-vfp"))) ``` applied to a function, selects hardware FP calling convention. The AArch64 PCS standard variants do not change how parameters are passed, so no PCS attributes are supported. The pcs attribute applies to functions and function types. Implementations are allowed to treat the procedure call specification as part of the type, i.e. as a language linkage in the sense of [C++ \#1]. ## Target selection The following target selection attributes are supported: ``` c __attribute__((target("arm"))) ``` when applied to a function, forces A32 state code generation. ``` c __attribute__((target("thumb"))) ``` when applied to a function, forces T32 state code generation. The implementation must generate code in the required state unless it is impossible to do so. For example, on an Armv5 or Armv6 target with VFP (and without the T32 instruction set), if a function is forced to T32 state, any floating-point operations or intrinsics that are only available in A32 state must be generated as calls to library functions or compiler-generated functions. This attribute does not apply to AArch64. ## Function Multi Versioning The specification for Function Multi Versioning is in [**Beta** state](#current-status-and-anticipated-changes) and might change or be extended in the future. Function Multi Versioning provides a convenient way to select the most appropriate version of a function at runtime. All versions of the function may be in the final binary. The compiler generates all supported versions and the runtime makes the selection at load time. The following attributes trigger the multi version code generation: `__attribute__((target_version("name")))` and `__attribute__((target_clones("name",...)))`. * These attributes can be mixed with each other. * The `default` version means the version of the function that would be generated without these attributes. * `name` is the dependent features from the tables below. * If a feature depends on another feature as defined by the Architecture Reference Manual then no need to explicitly state in the attribute[^fmv-note-names]. * The dependent features could be joined by the `+` sign. * None of these attributes will enable the corresponding ACLE feature(s) associated to the `name` expressed in the attribute. * These attributes have no effect on the calling convention. * All versions must use the same calling convention. * If only the `default` version exist it should be linked directly. * FMV may be disabled in compile time by a compiler flag. In this case the `default` version shall be used. [^fmv-note-names]: For example the `sve_bf16` feature depends on `sve` but it is enough to say `target_version("sve_bf16")` in the code. The attribute `__attribute__((target_version("name")))` expresses the following: * when applied to a function it becomes one of the versions. Function with the same name may exist with multiple versions in the same translation unit. * Function versions may reside in different translation units. * Each version declaration should be visible at the translation unit in which the corresponding function version resides. * One `default` version of the function is required to be provided in one of the translation units. * Implicitly, without this attribute, * or explicitly providing the `default` in the attribute. * All instances of the versions shall share the same function signature and calling convention. The attribute `__attribute__((target_clones("name",...)))` expresses the following: * when applied to a function the compiler emits multiple versions based on the arguments. * One of them is implicitly the `default`. * If the `default` matches with another explicitly provided version in the same translation unit, then the compiler can emit only one function instead of the two. The explicitly provided version shall be preferred. * If a name is not recognized the compiler should ignore it[^fmv-note-ignore]. [^fmv-note-ignore]: The intention is to support the usecase of newer code if compiled with an older compiler. The compiler may provide diagnostic messages and could block the compilation (e.g. if the `-pedantic` flag is present). `__HAVE_FUNCTION_MULTI_VERSIONING` is defined to 1 if the versioning mechanism described in this section is supported by the compiler and it is enabled. ### Name mangling The `"default"` version is mangled with `".default"` on top of the language-specific name mangling. All versioned functions with their mangled names are always resolvable. A function is expected to be resolvable with the original mangled name of the function. The mangling function is compatible with the mangling for version information of the [[cxxabi]](#cxxabi), and it is defined as follows: ``` := `.` := function name mangling for c/c++ := `_` followed by token obtained from the tables below and prefixed with `M` ``` If multiple features are requested then those shall be appended in lexicographic order and prefixed with `M`. The mangled name shall contain a unique set of features (duplication of features is not allowed). For example: ``` c __attribute__((target_clones("crc32", "aes+sha1"))) int foo(){..} ``` will produce these mangled names for C language: `foo.default`, `foo._Mcrc32`, `foo._MaesMsha1` while `foo` is a callable external symbol which leads to one of the versioned functions. ### Mapping The following table lists the architectures feature mapping for AArch32 | **Priority** | **Architecture name** | **Name** | **Dependent feature registers** | | ------------ | -------------------------------- | --------------- | ------------------------------- | | 0 | N/A | default | N/A | | 90 | CRC32 instructions | crc | ```ID_ISAR5.CRC32 == 0b0001``` | | 100 | SHA1 instructions | sha1 | ```ID_ISAR5.SHA1 == 0b0001``` | | 110 | SHA2 instructions | sha2 | ```ID_ISAR5.SHA2 == 0b0001``` | | 120 | AES instructions | aes | ```ID_ISAR5.AES >= 0b0001``` | | 130 | VMULL (polynomial) instructions | vmull | ```ID_ISAR5.AES == 0b0002``` | The following table lists the architectures feature mapping for AArch64 | **Priority** | **Architecture name** | **Name** | **Dependent feature registers** | | ------------- | ------------------------ | ------------- | ----------------------------------------- | | 0 | N/A | default | N/A | | 10 | `FEAT_RNG` | rng | ```ID_AA64ISAR0_EL1.RNDR == 0b0001``` | | 20 | `FEAT_FlagM` | flagm | ```ID_AA64ISAR0_EL1.TS == 0b0001 OR ```
```ID_AA64ISAR0_EL1.TS == 0b0010``` | | 30 | `FEAT_FlagM2` | flagm2 | ```ID_AA64ISAR0_EL1.TS == 0b0010``` | | 80 | `FEAT_LSE` | lse | ```ID_AA64ISAR0_EL1.Atomic == 0b0001``` | | 90 | Floating-point | fp | ```ID_AA64PFR0_EL1.FP != 0b1111``` | | 100 | `FEAT_AdvSIMD` | simd | ```ID_AA64PFR0_EL1.AdvSIMD != 0b1111``` | | 104 | `FEAT_DotProd` | dotprod | ```ID_AA64ISAR0_EL1.DP == 0b0001``` | | 106 | `FEAT_SM3`, `FEAT_SM4` | sm4 | ```ID_AA64ISAR0_EL1.SM4 == 0b0001 AND ```
```ID_AA64ISAR0_EL1.SM3 == 0b0001``` | | 108 | `FEAT_RDM` | rdm, rdma | ```ID_AA64ISAR0_EL1.RDM == 0b0001``` | | 110 | `FEAT_CRC32` | crc | ```ID_AA64ISAR0_EL1.CRC32 == 0b0001``` | | 120 | `FEAT_SHA1` | sha1 | ```ID_AA64ISAR0_EL1.SHA1 == 0b0001``` | | 130 | `FEAT_SHA256` | sha2 | ```ID_AA64ISAR0_EL1.SHA2 == 0b0001``` | | 140 | `FEAT_SHA512`,`FEAT_SHA3`| sha3 | ```ID_AA64ISAR0_EL1.SHA3 != 0b0000``` | | 150 | `FEAT_AES` | aes | ```ID_AA64ISAR0_EL1.AES >= 0b0001``` | | 160 | `FEAT_PMULL` | pmull | ```ID_AA64ISAR0_EL1.AES == 0b0010``` | | 170 | `FEAT_FP16` | fp16 | ```ID_AA64PFR0_EL1.FP == 0b0001``` | | 175 | `FEAT_FHM` | fp16fml | ```ID_AA64ISAR0_EL1.FHM == 0b0001``` | | 180 | `FEAT_DIT` | dit | ```ID_AA64PFR0_EL1.DIT == 0b0001``` | | 190 | `FEAT_DPB` | dpb | ```ID_AA64ISAR1_EL1.DPB >= 0b0001``` | | 200 | `FEAT_DPB2` | dpb2 | ```ID_AA64ISAR1_EL1.DPB == 0b0010``` | | 210 | `FEAT_JSCVT` | jscvt | ```ID_AA64ISAR1_EL1.JSCVT == 0b0001``` | | 220 | `FEAT_FCMA` | fcma | ```ID_AA64ISAR1_EL1.FCMA == 0b0001``` | | 230 | `FEAT_LRCPC` | rcpc | ```ID_AA64ISAR1_EL1.LRCPC != 0b0000``` | | 240 | `FEAT_LRCPC2` | rcpc2 | ```ID_AA64ISAR1_EL1.LRCPC == 0b0010``` | | 241 | `FEAT_LRCPC3` | rcpc3 | ```ID_AA64ISAR1_EL1.LRCPC == 0b0011``` | | 250 | `FEAT_FRINTTS` | frintts | ```ID_AA64ISAR1_EL1.FRINTTS == 0b0001``` | | 260 | `FEAT_DGH` | dgh | ```ID_AA64ISAR1_EL1.DGH == 0b0001``` | | 270 | `FEAT_I8MM` | i8mm | ```ID_AA64ISAR1_EL1.I8MM == 0b0001``` | | 280 | `FEAT_BF16` | bf16 | ```ID_AA64ISAR1_EL1.BF16 != 0b0000``` | | 290 | `FEAT_EBF16` | ebf16 | ```ID_AA64ISAR1_EL1.BF16 == 0b0010``` | | 300 | `FEAT_RPRES` | rpres | ```ID_AA64ISAR2_EL1.RPRES == 0b0001``` | | 310 | `FEAT_SVE` | sve | ```ID_AA64PFR0_EL1.SVE != 0b0000 AND ```
```ID_AA64ZFR0_EL1.SVEver == 0b0000``` | | 320 | `FEAT_BF16` | sve-bf16 | ```ID_AA64ZFR0_EL1.BF16 != 0b0000``` | | 330 | `FEAT_EBF16` | sve-ebf16 | ```ID_AA64ZFR0_EL1.BF16 == 0b0010``` | | 340 | `FEAT_I8MM` | sve-i8mm | ```ID_AA64ZFR0_EL1.I8MM == 0b00001``` | | 350 | `FEAT_F32MM` | f32mm | ```ID_AA64ZFR0_EL1.F32MM == 0b00001``` | | 360 | `FEAT_F64MM` | f64mm | ```ID_AA64ZFR0_EL1.F64MM == 0b00001``` | | 370 | `FEAT_SVE2` | sve2 | ```ID_AA64PFR0_EL1.SVE != 0b0000 AND ```
```ID_AA64ZFR0_EL1.SVEver == 0b0001``` | | 380 | `FEAT_SVE_AES` | sve2-aes | ```ID_AA64ZFR0_EL1.AES == 0b0001 OR ```
```ID_AA64ZFR0_EL1.AES == 0b0010``` | | 390 | `FEAT_SVE_PMULL128` | sve2-pmull128 | ```ID_AA64ZFR0_EL1.AES == 0b0010``` | | 400 | `FEAT_SVE_BitPerm` | sve2-bitperm | ```ID_AA64ZFR0_EL1.BitPerm == 0b0001``` | | 410 | `FEAT_SVE_SHA3` | sve2-sha3 | ```ID_AA64ZFR0_EL1.SHA3 == 0b0001``` | | 420 | `FEAT_SM3`,`FEAT_SVE_SM4`| sve2-sm4 | ```ID_AA64ZFR0_EL1.SM4 == 0b0001``` | | 430 | `FEAT_SME` | sme | ```ID_AA64PFR1_EL1.SME == 0b0001``` | | 440 | `FEAT_MTE` | memtag | ```ID_AA64PFR1_EL1.MTE >= 0b0001``` | | 450 | `FEAT_MTE2` | memtag2 | ```ID_AA64PFR1_EL1.MTE >= 0b0010``` | | 460 | `FEAT_MTE3` | memtag3 | ```ID_AA64PFR1_EL1.MTE >= 0b0011``` | | 470 | `FEAT_SB` | sb | ```ID_AA64ISAR1_EL1.SB == 0b0001``` | | 480 | `FEAT_SPECRES` | predres | ```ID_AA64ISAR1_EL1.SPECRES == 0b0001``` | | 490 | `FEAT_SSBS` | ssbs | ```ID_AA64PFR1_EL1.SSBS == 0b0001``` | | 500 | `FEAT_SSBS2` | ssbs2 | ```ID_AA64PFR1_EL1.SSBS == 0b0010``` | | 510 | `FEAT_BTI` | bti | ```ID_AA64PFR1_EL1.BT == 0b0001``` | | 520 | `FEAT_LS64` | ls64 | ```ID_AA64ISAR1_EL1.LS64 >= 0b0001``` | | 530 | `FEAT_LS64_V` | ls64_v | ```ID_AA64ISAR1_EL1.LS64 >= 0b0010``` | | 540 | `FEAT_LS64_ACCDATA` | ls64_accdata | ```ID_AA64ISAR1_EL1.LS64 >= 0b0011``` | | 550 | `FEAT_WFxT` | wfxt | ```ID_AA64ISAR2_EL1.WFxT == 0b0001``` | | 560 | `FEAT_SME_F64F64` | sme-f64f64 | ```ID_AA64SMFR0_EL1.F64F64 == 0b0001``` | | 570 | `FEAT_SME_I16I64` | sme-i16i64 | ```ID_AA64SMFR0_EL1.I16I64 == 0b1111``` | | 580 | `FEAT_SME2` | sme2 | ```ID_AA64PFR1_EL1.SME == 0b0010``` | | 650 | `FEAT_MOPS` | mops | ```ID_AA64ISAR2_EL1.MOPS == 0b0001``` | ### Selection The following rules shall be followed by all implementations: 1. Implementation of the selection algorithm is platform dependent, where with platform means CPU/Vendor/OS as in the target triplet. 2. The selection is permanent for the lifetime of the process. 3. Only those versions could be considered where all dependent features are available. Rules of version selection are in order: 4. Select the most specific version else 5. select the version with the highest priority else 6. `"default"` is selected if no other versions are suitable. ## Weak linkage `__attribute__((weak))` can be attached to declarations and definitions to indicate that they have weak static linkage (`STB_WEAK` in ELF objects). As definitions, they can be overridden by other definitions of the same symbol. As references, they do not need to be satisfied and will be resolved to zero if a definition is not present. ### Patchable constants In addition, this specification requires that weakly defined initialized constants are not used for constant propagation, allowing the value to be safely changed by patching after the object is produced. ## Alignment The new standards for C [[C11]](#C11) (6.7.5) and C++ [[CPP11]](#CPP11) (7.6.2) add syntax for aligning objects and types. ACLE provides an alternative syntax described in this section. ### Alignment attribute `__attribute__((aligned(N)))` can be associated with data, functions, types and fields. N must be an integral constant expression and must be a power of 2, for example 1, 2, 4, 8. The maximum alignment depends on the storage class of the object being aligned. The size of a data type is always a multiple of its alignment. This is a consequence of the rule in C that the spacing between array elements is equal to the element size. The aligned attribute does not act as a type qualifier. For example, given ``` c char x __attribute__((aligned(8))); int y __attribute__((aligned(1))); ``` the type of `&x` is `char *` and the type of `&y` is `int *`. The following declarations are equivalent: ``` c struct S x __attribute__((aligned(16))); /* ACLE */ struct S _Alignas(16) x/* C11 */ #include /* C11 (alternative) */ struct S alignas(16) x; struct S alignas(16) x; /* C++11 */ ``` ### Alignment of static objects The macro `__ARM_ALIGN_MAX_PWR` indicates (as the exponent of a power of 2) the maximum available alignment of static data -- for example 4 for 16-byte alignment. So the following is always valid: ``` c int x __attribute__((aligned(1 << __ARM_ALIGN_MAX_PWR))); ``` or, using the C11/C++11 syntax: ``` c alignas(1 << __ARM_ALIGN_MAX_PWR) int x; ``` Since an alignment request on an object does not change its type or size, x in this example would have type int and size 4. There is in principle no limit on the alignment of static objects, within the constraints of available memory. In the Arm ABI an object with a requested alignment would go into an ELF section with at least as strict an alignment requirement. However, an implementation supporting position-independent dynamic objects or overlays may need to place restrictions on their alignment demands. ### Alignment of stack objects It must be possible to align any local object up to the stack alignment as specified in the AAPCS for AArch32 (i.e. 8 bytes) or as specified in AAPCS64 for AArch64 (i.e. 16 bytes) this being also the maximal alignment of any native type. An implementation may, but is not required to, permit the allocation of local objects with greater alignment, for example 16 or 32 bytes for AArch32. (This would involve some runtime adjustment such that the object address was not a fixed offset from the stack pointer on entry.) If a program requests alignment greater than the implementation supports, it is recommended that the compiler warn but not fault this. Programmers should expect over-alignment of local objects to be treated as a hint. The macro `__ARM_ALIGN_MAX_STACK_PWR` indicates (as the exponent of a power of 2) the maximum available stack alignment. For example, a value of 3 indicates 8-byte alignment. ### Procedure calls For procedure calls, where a parameter has aligned type, data should be passed as if it was a basic type of the given type and alignment. For example, given the aligned type: ``` c struct S { int a[2]; } __attribute__((aligned(8))); ``` the second argument of: ``` c f(int, struct S); ``` should be passed as if it were: ``` c f(int, long long); ``` which means that in AArch32 AAPCS the second parameter is in `R2/R3` rather than `R1/R2`. ### Alignment of C heap storage The standard C allocation functions [[C99]](#C99) (7.20.3), such as malloc(), return storage aligned to the normal maximal alignment, i.e. the largest alignment of any (standard) type. Implementations may, but are not required to, provide a function to return heap storage of greater alignment. Suitable functions are: ``` c int posix_memalign(void **memptr, size_t alignment, size_t size ); ``` as defined in [[POSIX]](#POSIX), or: ``` c void *aligned_alloc(size_t alignment, size_t size); ``` as defined in [[C11]](#C11) (7.22.3.1). ### Alignment of C++ heap allocation In C++, an allocation (with new) knows the object's type. If the type is aligned, the allocation should also be aligned. There are two cases to consider depending on whether the user has provided an allocation function. If the user has provided an allocation function for an object or array of over-aligned type, it is that function's responsibility to return suitably aligned storage. The size requested by the runtime library will be a multiple of the alignment (trivially so, for the non-array case). (The AArch32 C++ ABI does not explicitly deal with the runtime behavior when dealing with arrays of alignment greater than 8. In this situation, any cookie will be 8 bytes as usual, immediately preceding the array; this means that the cookie is not necessarily at the address seen by the allocation and deallocation functions. Implementations will need to make some adjustments before and after calls to the ABI-defined C++ runtime, or may provide additional non-standard runtime helper functions.) Example: ``` c struct float4 { void *operator new[](size_t s) { void *p; posix_memalign(&p, 16, s); return p; } float data[4]; } __attribute__((aligned(16))); ``` If the user has not provided their own allocation function, the behavior is implementation-defined. The generic itanium C++ ABI, which we use in AArch64, already handles arrays with arbitrarily aligned elements ## Scalable Vector Extension procedure call standard attribute On SVE enabled AArch64 targets, the [[AAPCS64]](#AAPCS64) allows procedure calls to use the SVE calling convention. If a subroutine takes at least one argument in scalable vector registers or scalable predicate registers, or if the subroutine is a function that returns results in such registers, the subroutine must ensure that the entire contents of `z8-z23` and `p4-15` are preserved across the call. This calling convention is described in sections 6.1.3 and 6.1.4 of [AAPCS64](#AAPCS64) (see [release 2022Q1](https://github.com/ARM-software/abi-aa/releases/tag/2022Q1)). The ACLE allows this to be enforced per function and adds the following function attribute to a function declaration or definition: ``` c __attribute__(("aarch64_sve_pcs")) ``` ## Other attributes The following attributes should be supported and their definitions follow [[GCC]](#GCC). These attributes are not specific to Arm or the Arm ABI. `alias`, `common`, `nocommon`, `noinline`, `packed`, `section`, `visibility`, `weak` Some specific requirements on the weak attribute are detailed in [Weak linkage](#weak-linkage). # Synchronization, barrier, and hint intrinsics ## Introduction This section provides intrinsics for managing data that may be accessed concurrently between processors, or between a processor and a device. Some intrinsics atomically update data, while others place barriers around accesses to data to ensure that accesses are visible in the correct order. Memory prefetch intrinsics are also described in this section. ## Atomic update primitives ### C/C++ standard atomic primitives The new C and C++ standards [[C11]](#C11) (7.17), [[CPP11]](#CPP11) (clause 29) provide a comprehensive library of atomic operations and barriers, including operations to read and write data with particular ordering requirements. Programmers are recommended to use this where available. ### IA-64/GCC atomic update primitives The `__sync` family of intrinsics (introduced in [[IA-64]](#IA-64) (section 7.4), and as documented in the GCC documentation) may be provided, especially if the C/C++ atomics are not available, and are recommended as being portable and widely understood. These may be expanded inline, or call library functions. Note that, unusually, these intrinsics are polymorphic they will specialize to instructions suitable for the size of their arguments. ## Memory barriers Memory barriers ensure specific ordering properties between memory accesses. For more details on memory barriers, see [ARMARM] (A3.8.3). The intrinsics in this section are available for all targets. They may be no-ops (i.e. generate no code, but possibly act as a code motion barrier in compilers) on targets where the relevant instructions do not exist, but only if the property they guarantee would have held anyway. On targets where the relevant instructions exist but are implemented as no-ops, these intrinsics generate the instructions. The memory barrier intrinsics take a numeric argument indicating the scope and access type of the barrier, as shown in the following table. (The assembler mnemonics for these numbers, as shown in the table, are not available in the intrinsics.) The argument should be an integral constant expression within the required range see [Constant arguments to intrinsics](#constant-arguments-to-intrinsics). | **Argument** | **Mnemonic** | **Domain** | **Ordered Accesses (before-after)** | | ------------ | ------------ | --------------- | ----------------------------------- | | 15 | SY | Full system | Any-Any | | 14 | ST | Full system | Store-Store | | 13 | LD | Full system | Load-Load, Load-Store | | 11 | ISH | Inner shareable | Any-Any | | 10 | ISHST | Inner shareable | Store-Store | | 9 | ISHLD | Inner shareable | Load-Load, Load-Store | | 7 | NSH or UN | Non-shareable | Any-Any | | 6 | NSHST | Non-shareable | Store-Store | | 5 | NSHLD | Non-shareable | Load-Load, Load-Store | | 3 | OSH | Outer shareable | Any-Any | | 2 | OSHST | Outer shareable | Store-Store | | 1 | OSHLD | Outer shareable | Load-Load, Load-Store | The following memory barrier intrinsics are available: ``` c void __dmb(/*constant*/ unsigned int); ``` Generates a DMB (data memory barrier) instruction or equivalent CP15 instruction. DMB ensures the observed ordering of memory accesses. Memory accesses of the specified type issued before the DMB are guaranteed to be observed (in the specified scope) before memory accesses issued after the DMB. For example, DMB should be used between storing data, and updating a flag variable that makes that data available to another core. The `__dmb()` intrinsic also acts as a compiler memory barrier of the appropriate type. ``` c void __dsb(/*constant*/ unsigned int); ``` Generates a DSB (data synchronization barrier) instruction or equivalent CP15 instruction. DSB ensures the completion of memory accesses. A DSB behaves as the equivalent DMB and has additional properties. After a DSB instruction completes, all memory accesses of the specified type issued before the DSB are guaranteed to have completed. The `__dsb()` intrinsic also acts as a compiler memory barrier of the appropriate type. ``` c void __isb(/*constant*/ unsigned int); ``` Generates an ISB (instruction synchronization barrier) instruction or equivalent CP15 instruction. This instruction flushes the processor pipeline fetch buffers, so that following instructions are fetched from cache or memory. An ISB is needed after some system maintenance operations. An ISB is also needed before transferring control to code that has been loaded or modified in memory, for example by an overlay mechanism or just-in-time code generator. (Note that if instruction and data caches are separate, privileged cache maintenance operations would be needed in order to unify the caches.) The only supported argument for the `__isb()` intrinsic is 15, corresponding to the SY (full system) scope of the ISB instruction. ### Examples In this example, process `P1` makes some data available to process `P2` and sets a flag to indicate this. ``` c P1: value = x; /* issue full-system memory barrier for previous store: setting of flag is guaranteed not to be observed before write to value */ __dmb(14); flag = true; P2: /* busy-wait until the data is available */ while (!flag) {} /* issue full-system memory barrier: read of value is guaranteed not to be observed by memory system before read of flag */ __dmb(15); /* use value */; ``` In this example, process `P1` makes data available to `P2` by putting it on a queue. ``` c P1: work = new WorkItem; work->payload = x; /* issue full-system memory barrier for previous store: consumer cannot observe work item on queue before write to work item's payload */ __dmb(14); queue_head = work; P2: /* busy-wait until work item appears */ while (!(work = queue_head)) {} /* no barrier needed: load of payload is data-dependent */ /* use work->payload */ ``` ## Hints The intrinsics in this section are available for all targets. They may be no-ops (i.e. generate no code, but possibly act as a code motion barrier in compilers) on targets where the relevant instructions do not exist. On targets where the relevant instructions exist but are implemented as no-ops, these intrinsics generate the instructions. ``` c void __wfi(void); ``` Generates a WFI (wait for interrupt) hint instruction, or nothing. The WFI instruction allows (but does not require) the processor to enter a low-power state until one of a number of asynchronous events occurs. ``` c void __wfe(void); ``` Generates a WFE (wait for event) hint instruction, or nothing. The WFE instruction allows (but does not require) the processor to enter a low-power state until some event occurs such as a SEV being issued by another processor. ``` c void __sev(void); ``` Generates a SEV (send a global event) hint instruction. This causes an event to be signaled to all processors in a multiprocessor system. It is a NOP on a uniprocessor system. ``` c void __sevl(void); ``` Generates a send a local event hint instruction. This causes an event to be signaled to only the processor executing this instruction. In a multiprocessor system, it is not required to affect the other processors. ``` c void __yield(void); ``` Generates a YIELD hint instruction. This enables multithreading software to indicate to the hardware that it is performing a task, for example a spin-lock, that could be swapped out to improve overall system performance. ``` c void __dbg(/*constant*/ unsigned int); ``` Generates a DBG instruction. This provides a hint to debugging and related systems. The argument must be a constant integer from 0 to 15 inclusive. See implementation documentation for the effect (if any) of this instruction and the meaning of the argument. This is available only when compiling for AArch32. ## Swap `__swp` is available for all targets. This intrinsic expands to a sequence equivalent to the deprecated (and possibly unavailable) SWP instruction. ``` c uint32_t __swp(uint32_t, volatile void *); ``` Unconditionally stores a new value at the given address, and returns the old value. As with the IA-64/GCC primitives described in 0, the `__swp` intrinsic is polymorphic. The second argument must provide the address of a byte-sized object or an aligned word-sized object and it must be possible to determine the size of this object from the argument expression. This intrinsic is implemented by LDREX/STREX (or LDREXB/STREXB) where available, as if by ``` c uint32_t __swp(uint32_t x, volatile uint32_t *p) { uint32_t v; /* use LDREX/STREX intrinsics not specified by ACLE */ do v = __ldrex(p); while (__strex(x, p)); return v; } ``` or alternatively, ``` c uint32_t __swp(uint32_t x, uint32_t *p) { uint32_t v; /* use IA-64/GCC atomic builtins */ do v = *p; while (!__sync_bool_compare_and_swap(p, v, x)); return v; } ``` It is recommended that compilers should produce a downgradeable/upgradeable warning on encountering the `__swp` intrinsic. Only if load-store exclusive instructions are not available will the intrinsic use the SWP/SWPB instructions. It is strongly recommended to use standard and flexible atomic primitives such as those available in the C++ header. `__swp` is provided solely to allow straightforward (and possibly automated) replacement of explicit use of SWP in inline assembler. SWP is obsolete in the Arm architecture, and in recent versions of the architecture, may be configured to be unavailable in user-mode. (Aside: unconditional atomic swap is also less powerful as a synchronization primitive than load-exclusive/store-conditional.) ## Memory prefetch intrinsics Intrinsics are provided to prefetch data or instructions. The size of the data or function is ignored. Note that the intrinsics may be implemented as no-ops (i.e. not generate a prefetch instruction, if none is available). Also, even where the architecture does provide a prefetch instruction, a particular implementation may implement the instruction as a no-op (i.e. the instruction has no effect). ### Data prefetch ``` c void __pld(void const volatile *addr); ``` Generates a data prefetch instruction, if available. The argument should be any expression that may designate a data address. The data is prefetched to the innermost level of cache, for reading. ``` c void __pldx(/*constant*/ unsigned int /*access_kind*/, /*constant*/ unsigned int /*cache_level*/, /*constant*/ unsigned int /*retention_policy*/, void const volatile *addr); ``` Generates a data prefetch instruction. This intrinsic allows the specification of the expected access kind (read or write), the cache level to load the data, the data retention policy (temporal or streaming), The relevant arguments can only be one of the following values. | **Access Kind** | **Value** | **Summary** | | --------------- | --------- | ---------------------------------------- | | PLD | 0 | Fetch the addressed location for reading | | PST | 1 | Fetch the addressed location for writing | | Cache Level | Value | Summary | | ----------- | ----- | ------------------------------------------------------ | | L1 | 0 | Fetch the addressed location to L1 cache | | L2 | 1 | Fetch the addressed location to L2 cache | | L3 | 2 | Fetch the addressed location to L3 cache | | SLC | 3 | Fetch the addressed location to the System-Level Cache | | **Retention Policy** | **Value** | **Summary** | | -------------------- | --------- | -------------------------------------------------------------------------- | | KEEP | 0 | Temporal fetch of the addressed location (i.e. allocate in cache normally) | | STRM | 1 | Streaming fetch of the addressed location (i.e. memory used only once) | ### Instruction prefetch ``` c void __pli(T addr); ``` Generates a code prefetch instruction, if available. If a specific code prefetch instruction is not available, this intrinsic may generate a data-prefetch instruction to fetch the addressed code to the innermost level of unified cache. It will not fetch code to data-cache in a split cache level. ``` c void __plix(/*constant*/ unsigned int /*cache_level*/, /*constant*/ unsigned int /*retention_policy*/, T addr); ``` Generates a code prefetch instruction. This intrinsic allows the specification of the cache level to load the code, the retention policy (temporal or streaming). The relevant arguments can have the same values as in `__pldx`. `__pldx` and `__plix` arguments cache level and retention policy are ignored on unsupported targets. ## NOP ``` c void __nop(void); ``` Generates an unspecified no-op instruction. Note that not all architectures provide a distinguished NOP instruction. On those that do, it is unspecified whether this intrinsic generates it or another instruction. It is not guaranteed that inserting this instruction will increase execution time. # Data-processing intrinsics The intrinsics in this section are provided for algorithm optimization. The `` header should be included before using these intrinsics. Implementations are not required to introduce precisely the instructions whose names match the intrinsics. However, implementations should aim to ensure that a computation expressed compactly with intrinsics will generate a similarly compact sequence of machine code. In general, C's as-if rule [[C99]](#C99) (5.1.2.3) applies, meaning that the compiled code must behave *as if* the instruction had been generated. In general, these intrinsics are aimed at DSP algorithm optimization on M-profile and R-profile. Use on A-profile is deprecated. However, the miscellaneous intrinsics and CRC32 intrinsics described in [Miscellaneous data-processing intrinsics](#miscellaneous-data-processing-intrinsics) and [CRC32 intrinsics](#crc32-intrinsics) respectively are suitable for all profiles. ## Programmer's model of global state ### The Q (saturation) flag The Q flag is a cumulative (sticky) saturation bit in the APSR (Application Program Status Register) indicating that an operation saturated, or in some cases, overflowed. It is set on saturation by most intrinsics in the DSP and SIMD intrinsic sets, though some SIMD intrinsics feature saturating operations which do not set the Q flag. [[AAPCS]](#AAPCS) (5.1.1) states: The N, Z, C, V and Q flags (bits 27-31) and the GE[3:0] bits (bits 16-19) are undefined on entry to or return from a public interface. Note that this does not state that these bits (in particular the Q flag) are undefined across any C/C++ function call boundary only across a public interface. The Q and GE bits could be manipulated in well-defined ways by local functions, for example when constructing functions to be used in DSP algorithms. Implementations must avoid introducing instructions (such as SSAT/USAT, or SMLABB) which affect the Q flag, if the programmer is testing whether the Q flag was set by explicit use of intrinsics and if the implementation's introduction of an instruction may affect the value seen. The implementation might choose to model the definition and use (liveness) of the Q flag in the way that it models the liveness of any visible variable, or it might suppress introduction of Q-affecting instructions in any routine in which the Q flag is tested. ACLE does not define how or whether the Q flag is preserved across function call boundaries. (This is seen as an area for future specification.) In general, the Q flag should appear to C/C++ code in a similar way to the standard floating-point cumulative exception flags, as global (or thread-local) state that can be tested, set or reset through an API. The following intrinsics are available when `__ARM_FEATURE_QBIT` is defined: int ```__saturation_occurred(void);``` Returns 1 if the Q flag is set, 0 if not. void ```__set_saturation_occurred(int);``` Sets or resets the Q flag according to the LSB of the value. `__set_saturation_occurred(0)` might be used before performing a sequence of operations after which the Q flag is tested. (In general, the Q flag cannot be assumed to be unset at the start of a function.) void ```__ignore_saturation(void);``` This intrinsic is a hint and may be ignored. It indicates to the compiler that the value of the Q flag is not live (needed) at or subsequent to the program point at which the intrinsic occurs. It may allow the compiler to remove preceding instructions, or to change the instruction sequence in such a way as to result in a different value of the Q flag. (A specific example is that it may recognize clipping idioms in C code and implement them with an instruction such as SSAT that may set the Q flag.) ### The GE flags The GE (Greater than or Equal to) flags are four bits in the APSR. They are used with the 32-bit SIMD intrinsics described in [32-bit SIMD Operations](#32-bit-simd-operations). There are four GE flags, one for each 8-bit lane of a 32-bit SIMD operation. Certain non-saturating 32-bit SIMD intrinsics set the GE bits to indicate overflow of addition or subtraction. For 4x8-bit operations the GE bits are set one for each byte. For 2x16-bit operations the GE bits are paired together, one for the high halfword and the other pair for the low halfword. The only supported way to read or use the GE bits (in this specification) is by using the `__sel` intrinsic, see [Parallel selection](#parallel-selection). ### Floating-point environment An implementation should implement the features of for accessing the floating-point runtime environment. Programmers should use this rather than accessing the VFP FPSCR directly. For example, on a target supporting VFP the cumulative exception flags (for example IXC, OFC) can be read from the FPSCR by using the fetestexcept() function, and the rounding mode (RMode) bits can be read using the fegetround() function. ACLE does not support changing the DN, FZ or AHP bits at runtime. VFP short vector mode (enabled by setting the Stride and Len bits) is deprecated, and is unavailable on later VFP implementations. ACLE provides no support for this mode. ## Miscellaneous data-processing intrinsics The following intrinsics perform general data-processing operations. They have no effect on global state. \[Note: documentation of the `__nop` intrinsic has moved to [NOP](#nop)] For completeness and to aid portability between LP64 and LLP64 models, ACLE also defines intrinsics with `l` suffix. ``` c uint32_t __ror(uint32_t x, uint32_t y); unsigned long __rorl(unsigned long x, uint32_t y); uint64_t __rorll(uint64_t x, uint32_t y); ``` Rotates the argument `x` right by `y` bits. `y` can take any value. These intrinsics are available on all targets. ``` c unsigned int __clz(uint32_t x); unsigned int __clzl(unsigned long x); unsigned int __clzll(uint64_t x); ``` Returns the number of leading zero bits in `x`. When `x` is zero it returns the argument width, i.e. 32 or 64. These intrinsics are available on all targets. On targets without the CLZ instruction it should be implemented as an instruction sequence or a call to such a sequence. A suitable sequence can be found in [Warren](#Warren) (fig. 5-7). Hardware support for these intrinsics is indicated by `__ARM_FEATURE_CLZ`. ``` c unsigned int __cls(uint32_t x); unsigned int __clsl(unsigned long x); unsigned int __clsll(uint64_t x); ``` Returns the number of leading sign bits in `x`. When `x` is zero it returns the argument width - 1, i.e. 31 or 63. These intrinsics are available on all targets. On targets without the CLZ instruction it should be implemented as an instruction sequence or a call to such a sequence. Fast hardware implementation (using a CLS instruction or a short code sequence involving the CLZ instruction) is indicated by `__ARM_FEATURE_CLZ`. ``` c uint32_t __rev(uint32_t); unsigned long __revl(unsigned long); uint64_t __revll(uint64_t); ``` Reverses the byte order within a word or doubleword. These intrinsics are available on all targets and should be expanded to an efficient straight-line code sequence on targets without byte reversal instructions. ``` c uint32_t __rev16(uint32_t); unsigned long __rev16l(unsigned long); uint64_t __rev16ll(uint64_t); ``` Reverses the byte order within each halfword of a word. For example, `0x12345678` becomes `0x34127856`. These intrinsics are available on all targets and should be expanded to an efficient straight-line code sequence on targets without byte reversal instructions. ``` c int16_t __revsh(int16_t); ``` Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, `0x0080` becomes `0x8000`. This intrinsic is available on all targets and should be expanded to an efficient straight-line code sequence on targets without byte reversal instructions. ``` c uint32_t __rbit(uint32_t x); unsigned long __rbitl(unsigned long x); uint64_t __rbitll(uint64_t x); ``` Reverses the bits in `x`. These intrinsics are only available on targets with the RBIT instruction. ### Examples ``` c #ifdef __ARM_BIG_ENDIAN #define htonl(x) (uint32_t)(x) #define htons(x) (uint16_t)(x) #else /* little-endian */ #define htonl(x) __rev(x) #define htons(x) (uint16_t)__revsh(x) #endif /* endianness */ #define ntohl(x) htonl(x) #define ntohs(x) htons(x) /* Count leading sign bits */ inline unsigned int count_sign(int32_t x) { return __clz(x ^ (x << 1)); } /* Count trailing zeroes */ inline unsigned int count_trail(uint32_t x) { #if (__ARM_ARCH >= 6 && __ARM_ISA_THUMB >= 2) || __ARM_ARCH >= 7 /* RBIT is available */ return __clz(__rbit(x)); #else unsigned int n = __clz(x & -x); /* get the position of the last bit */ return n == 32 ? n : (31-n); #endif } ``` ## 16-bit multiplications The intrinsics in this section provide direct access to the 16x16 and 16x32 bit multiplies introduced in Armv5E. Compilers are also encouraged to exploit these instructions from C code. These intrinsics are available when `__ARM_FEATURE_DSP` is defined, and are not available on non-5E targets. These multiplies cannot overflow. ``` c int32_t __smulbb(int32_t, int32_t); ``` Multiplies two 16-bit signed integers, i.e. the low halfwords of the operands. ``` c int32_t __smulbt(int32_t, int32_t); ``` Multiplies the low halfword of the first operand and the high halfword of the second operand. ``` c int32_t __smultb(int32_t, int32_t); ``` Multiplies the high halfword of the first operand and the low halfword of the second operand. ``` c int32_t __smultt(int32_t, int32_t); ``` Multiplies the high halfwords of the operands. ``` c int32_t __smulwb(int32_t, int32_t); ``` Multiplies the 32-bit signed first operand with the low halfword (as a 16-bit signed integer) of the second operand. Return the top 32 bits of the 48-bit product. ``` c int32_t __smulwt(int32_t, int32_t); ``` Multiplies the 32-bit signed first operand with the high halfword (as a 16-bit signed integer) of the second operand. Return the top 32 bits of the 48-bit product. ## Saturating intrinsics ### Width-specified saturation intrinsics These intrinsics are available when `__ARM_FEATURE_SAT` is defined. They saturate a 32-bit value at a given bit position. The saturation width must be an integral constant expression |--| see [Constant arguments to intrinsics](#constant-arguments-to-intrinsics). ``` c int32_t __ssat(int32_t, /*constant*/ unsigned int); ``` Saturates a signed integer to the given bit width in the range 1 to 32. For example, the result of saturation to 8-bit width will be in the range -128 to 127. The Q flag is set if the operation saturates. ``` c uint32_t __usat(int32_t, /*constant*/ unsigned int); ``` Saturates a signed integer to an unsigned (non-negative) integer of a bit width in the range 0 to 31. For example, the result of saturation to 8-bit width is in the range 0 to 255, with all negative inputs going to zero. The Q flag is set if the operation saturates. ### Saturating addition and subtraction intrinsics These intrinsics are available when `__ARM_FEATURE_DSP` is defined. The saturating intrinsics operate on 32-bit signed integer data. There are no special saturated or fixed point types. ``` c int32_t __qadd(int32_t, int32_t); ``` Adds two 32-bit signed integers, with saturation. Sets the Q flag if the addition saturates. ``` c int32_t __qsub(int32_t, int32_t); ``` Subtracts two 32-bit signed integers, with saturation. Sets the Q flag if the subtraction saturates. ``` c int32_t __qdbl(int32_t); ``` Doubles a signed 32-bit number, with saturation. `__qdbl(x)` is equal to `__qadd(x,x)` except that the argument x is evaluated only once. Sets the Q flag if the addition saturates. ### Accumulating multiplications These intrinsics are available when `__ARM_FEATURE_DSP` is defined. ``` c int32_t __smlabb(int32_t, int32_t, int32_t); ``` Multiplies two 16-bit signed integers, the low halfwords of the first two operands, and adds to the third operand. Sets the Q flag if the addition overflows. (Note that the addition is the usual 32-bit modulo addition which wraps on overflow, not a saturating addition. The multiplication cannot overflow.) ``` c int32_t __smlabt(int32_t, int32_t, int32_t); ``` Multiplies the low halfword of the first operand and the high halfword of the second operand, and adds to the third operand, as for `__smlabb`. ``` c int32_t __smlatb(int32_t, int32_t, int32_t); ``` Multiplies the high halfword of the first operand and the low halfword of the second operand, and adds to the third operand, as for `__smlabb`. ``` c int32_t __smlatt(int32_t, int32_t, int32_t); ``` Multiplies the high halfwords of the first two operands and adds to the third operand, as for `__smlabb`. ``` c int32_t __smlawb(int32_t, int32_t, int32_t); ``` Multiplies the 32-bit signed first operand with the low halfword (as a 16-bit signed integer) of the second operand. Adds the top 32 bits of the 48-bit product to the third operand. Sets the Q flag if the addition overflows. (See note for `__smlabb`). ``` c int32_t __smlawt(int32_t, int32_t, int32_t); ``` Multiplies the 32-bit signed first operand with the high halfword (as a 16-bit signed integer) of the second operand and adds the top 32 bits of the 48-bit result to the third operand as for `__smlawb`. ### Examples The ACLE DSP intrinsics can be used to define ETSI/ITU-T basic operations [[G.191]](#G.191): ``` c #include inline int32_t L_add(int32_t x, int32_t y) { return __qadd(x, y); } inline int32_t L_negate(int32_t x) { return __qsub(0, x); } inline int32_t L_mult(int16_t x, int16_t y) { return __qdbl(x*y); } inline int16_t add(int16_t x, int16_t y) { return (int16_t)(__qadd(x<<16, y<<16) >> 16); } inline int16_t norm_l(int32_t x) { return __clz(x ^ (x<<1)) & 31; } ... ``` This example assumes the implementation preserves the Q flag on return from an inline function. ## 32-bit SIMD Operations ### Availability Armv6 introduced instructions to perform 32-bit SIMD operations (i.e. two 16-bit operations or four 8-bit operations) on the Arm general-purpose registers. These instructions are not related to the much more versatile Advanced SIMD (Neon) extension, whose support is described in [Advanced SIMD (Neon) intrinsics](#advanced-simd-neon-intrinsics). The 32-bit SIMD intrinsics are available on targets featuring Armv6 and upwards, including the A and R profiles. In the M profile they are available in the Armv7E-M architecture. Availability of the 32-bit SIMD intrinsics implies availability of the saturating intrinsics. Availability of the SIMD intrinsics is indicated by the `__ARM_FEATURE_SIMD32` predefine. To access the intrinsics, the `` header should be included. ### Data types for 32-bit SIMD intrinsics The header `` should be included before using these intrinsics. The SIMD intrinsics generally operate on and return 32-bit words consisting of two 16-bit or four 8-bit values. These are represented as `int16x2_t` and `int8x4_t` below for illustration. Some intrinsics also feature scalar accumulator operands and/or results. When defining the intrinsics, implementations can define SIMD operands using a 32-bit integral type (such as `unsigned int`). The header `` defines typedefs `int16x2_t`, `uint16x2_t`, `int8x4_t`, and `uint8x4_t`. These should be defined as 32-bit integral types of the appropriate sign. There are no intrinsics provided to pack or unpack values of these types. This can be done with shifting and masking operations. ### Use of the Q flag by 32-bit SIMD intrinsics Some 32-bit SIMD instructions may set the Q flag described in [The Q (saturation) flag](#the-q-saturation-flag). The behavior of the intrinsics matches that of the instructions. Generally, instructions that perform lane-by-lane saturating operations do not set the Q flag. For example, `__qadd16` does not set the Q flag, even if saturation occurs in one or more lanes. The explicit saturation operations `__ssat` and `__usat` set the Q flag if saturation occurs. Similarly, `__ssat16` and `__usat16` set the Q flag if saturation occurs in either lane. Some instructions, such as `__smlad`, set the Q flag if overflow occurs on an accumulation, even though the accumulation is not a saturating operation (i.e. does not clip its result to the limits of the type). ### Parallel 16-bit saturation These intrinsics are available when `__ARM_FEATURE_SIMD32` is defined. They saturate two 16-bit values to a given bit width as for the `__ssat` and `__usat` intrinsics defined in [Width-specified saturation intrinsics](#width-specified-saturation-intrinsics). ``` c int16x2_t __ssat16(int16x2_t, /*constant*/ unsigned int); ``` Saturates two 16-bit signed values to a width in the range 1 to 16. The Q flag is set if either operation saturates. ``` c int16x2_t __usat16(int16x2_t, /*constant */ unsigned int); ``` Saturates two 16-bit signed values to a bit width in the range 0 to 15. The input values are signed and the output values are non-negative, with all negative inputs going to zero. The Q flag is set if either operation saturates. ### Packing and unpacking These intrinsics are available when `__ARM_FEATURE_SIMD32` is defined. ``` c int16x2_t __sxtab16(int16x2_t, int8x4_t); ``` Two values (at bit positions 0..7 and 16..23) are extracted from the second operand, sign-extended to 16 bits, and added to the first operand. ``` c int16x2_t __sxtb16(int8x4_t); ``` Two values (at bit positions 0..7 and 16..23) are extracted from the first operand, sign-extended to 16 bits, and returned as the result. ``` c uint16x2_t __uxtab16(uint16x2_t, uint8x4_t); ``` Two values (at bit positions 0..7 and 16..23) are extracted from the second operand, zero-extended to 16 bits, and added to the first operand. ``` c uint16x2_t __uxtb16(uint8x4_t); ``` Two values (at bit positions 0..7 and 16..23) are extracted from the first operand, zero-extended to 16 bits, and returned as the result. ### Parallel selection This intrinsic is available when `__ARM_FEATURE_SIMD32` is defined. ``` c uint8x4_t __sel(uint8x4_t, uint8x4_t); ``` Selects each byte of the result from either the first operand or the second operand, according to the values of the GE bits. For each result byte, if the corresponding GE bit is set then the byte from the first operand is used, otherwise the byte from the second operand is used. Because of the way that `int16x2_t` operations set two (duplicate) GE bits per value, the `__sel` intrinsic works equally well on `(u)int16x2_t` and `(u)int8x4_t` data. ### Parallel 8-bit addition and subtraction These intrinsics are available when `__ARM_FEATURE_SIMD32` is defined. Each intrinsic performs 8-bit parallel addition or subtraction. In some cases the result may be halved or saturated. ``` c int8x4_t __qadd8(int8x4_t, int8x4_t); ``` 4x8-bit addition, saturated to the range `-2**7` to `2**7-1`. ``` c int8x4_t __qsub8(int8x4_t, int8x4_t); ``` 4x8-bit subtraction, with saturation. ``` c int8x4_t __sadd8(int8x4_t, int8x4_t); ``` 4x8-bit signed addition. The GE bits are set according to the results. ``` c int8x4_t __shadd8(int8x4_t, int8x4_t); ``` 4x8-bit signed addition, halving the results. ``` c int8x4_t __shsub8(int8x4_t, int8x4_t); ``` 4x8-bit signed subtraction, halving the results. ``` c int8x4_t __ssub8(int8x4_t, int8x4_t); ``` 4x8-bit signed subtraction. The GE bits are set according to the results. ``` c uint8x4_t __uadd8(uint8x4_t, uint8x4_t); ``` 4x8-bit unsigned addition. The GE bits are set according to the results. ``` c uint8x4_t __uhadd8(uint8x4_t, uint8x4_t); ``` 4x8-bit unsigned addition, halving the results. ``` c uint8x4_t __uhsub8(uint8x4_t, uint8x4_t); ``` 4x8-bit unsigned subtraction, halving the results. ``` c uint8x4_t __uqadd8(uint8x4_t, uint8x4_t); ``` 4x8-bit unsigned addition, saturating to the range `0` to `2**8-1`. ``` c uint8x4_t __uqsub8(uint8x4_t, uint8x4_t); ``` 4x8-bit unsigned subtraction, saturating to the range `0` to `2**8-1`. ``` c uint8x4_t __usub8(uint8x4_t, uint8x4_t); ``` 4x8-bit unsigned subtraction. The GE bits are set according to the results. ### Sum of 8-bit absolute differences These intrinsics are available when `__ARM_FEATURE_SIMD32` is defined. They perform an 8-bit sum-of-absolute differences operation, typically used in motion estimation. ``` c uint32_t __usad8(uint8x4_t, uint8x4_t); ``` Performs 4x8-bit unsigned subtraction, and adds the absolute values of the differences together, returning the result as a single unsigned integer. ``` c uint32_t __usada8(uint8x4_t, uint8x4_t, uint32_t); ``` Performs 4x8-bit unsigned subtraction, adds the absolute values of the differences together, and adds the result to the third operand. ### Parallel 16-bit addition and subtraction These intrinsics are available when `__ARM_FEATURE_SIMD32` is defined. Each intrinsic performs 16-bit parallel addition and/or subtraction. In some cases the result may be halved or saturated. ``` c int16x2_t __qadd16(int16x2_t, int16x2_t); ``` 2x16-bit addition, saturated to the range `-2**15` to `2**15-1`. ``` c int16x2_t __qasx(int16x2_t, int16x2_t); ``` Exchanges halfwords of second operand, adds high halfwords and subtracts low halfwords, saturating in each case. ``` c int16x2_t __qsax(int16x2_t, int16x2_t); ``` Exchanges halfwords of second operand, subtracts high halfwords and adds low halfwords, saturating in each case. ``` c int16x2_t __qsub16(int16x2_t, int16x2_t); ``` 2x16-bit subtraction, with saturation. ``` c int16x2_t __sadd16(int16x2_t, int16x2_t); ``` 2x16-bit signed addition. The GE bits are set according to the results. ``` c int16x2_t __sasx(int16x2_t, int16x2_t); ``` Exchanges halfwords of the second operand, adds high halfwords and subtracts low halfwords. The GE bits are set according to the results. ``` c int16x2_t __shadd16(int16x2_t, int16x2_t); ``` 2x16-bit signed addition, halving the results. ``` c int16x2_t __shasx(int16x2_t, int16x2_t); ``` Exchanges halfwords of the second operand, adds high halfwords and subtract low halfwords, halving the results. ``` c int16x2_t __shsax(int16x2_t, int16x2_t); ``` Exchanges halfwords of the second operand, subtracts high halfwords and add low halfwords, halving the results. ``` c int16x2_t __shsub16(int16x2_t, int16x2_t); ``` 2x16-bit signed subtraction, halving the results. ``` c int16x2_t __ssax(int16x2_t, int16x2_t); ``` Exchanges halfwords of the second operand, subtracts high halfwords and adds low halfwords. The GE bits are set according to the results. ``` c int16x2_t __ssub16(int16x2_t, int16x2_t); ``` 2x16-bit signed subtraction. The GE bits are set according to the results. ``` c uint16x2_t __uadd16(uint16x2_t, uint16x2_t); ``` 2x16-bit unsigned addition. The GE bits are set according to the results. ``` c uint16x2_t __uasx(uint16x2_t, uint16x2_t); ``` Exchanges halfwords of the second operand, adds high halfwords and subtracts low halfwords. The GE bits are set according to the results of unsigned addition. ``` c uint16x2_t __uhadd16(uint16x2_t, uint16x2_t); ``` 2x16-bit unsigned addition, halving the results. ``` c uint16x2_t __uhasx(uint16x2_t, uint16x2_t); ``` Exchanges halfwords of the second operand, adds high halfwords and subtracts low halfwords, halving the results. ``` c uint16x2_t __uhsax(uint16x2_t, uint16x2_t); ``` Exchanges halfwords of the second operand, subtracts high halfwords and adds low halfwords, halving the results. ``` c uint16x2_t __uhsub16(uint16x2_t, uint16x2_t); ``` 2x16-bit unsigned subtraction, halving the results. ``` c uint16x2_t __uqadd16(uint16x2_t, uint16x2_t); ``` 2x16-bit unsigned addition, saturating to the range `0` to `2**16-1`. ``` c uint16x2_t __uqasx(uint16x2_t, uint16x2_t); ``` Exchanges halfwords of the second operand, and performs saturating unsigned addition on the high halfwords and saturating unsigned subtraction on the low halfwords. ``` c uint16x2_t __uqsax(uint16x2_t, uint16x2_t); ``` Exchanges halfwords of the second operand, and performs saturating unsigned subtraction on the high halfwords and saturating unsigned addition on the low halfwords. ``` c uint16x2_t __uqsub16(uint16x2_t, uint16x2_t); ``` 2x16-bit unsigned subtraction, saturating to the range `0` to `2**16-1`. ``` c uint16x2_t __usax(uint16x2_t, uint16x2_t); ``` Exchanges the halfwords of the second operand, subtracts the high halfwords and adds the low halfwords. Sets the GE bits according to the results of unsigned addition. ``` c uint16x2_t __usub16(uint16x2_t, uint16x2_t); ``` 2x16-bit unsigned subtraction. The GE bits are set according to the results. ### Parallel 16-bit multiplication These intrinsics are available when `__ARM_FEATURE_SIMD32` is defined. Each intrinsic performs two 16-bit multiplications. ``` c int32_t __smlad(int16x2_t, int16x2_t, int32_t); ``` Performs 2x16-bit multiplication and adds both results to the third operand. Sets the Q flag if the addition overflows. (Overflow cannot occur during the multiplications.) ``` c int32_t __smladx(int16x2_t, int16x2_t, int32_t); ``` Exchanges the halfwords of the second operand, performs 2x16-bit multiplication, and adds both results to the third operand. Sets the Q flag if the addition overflows. (Overflow cannot occur during the multiplications.) ``` c int64_t __smlald(int16x2_t, int16x2_t, int64_t); ``` Performs 2x16-bit multiplication and adds both results to the 64-bit third operand. Overflow in the addition is not detected. ``` c int64_t __smlaldx(int16x2_t, int16x2_t, int64_t); ``` Exchanges the halfwords of the second operand, performs 2x16-bit multiplication and adds both results to the 64-bit third operand. Overflow in the addition is not detected. ``` c int32_t __smlsd(int16x2_t, int16x2_t, int32_t); ``` Performs two 16-bit signed multiplications. Takes the difference of the products, subtracting the high-halfword product from the low-halfword product, and adds the difference to the third operand. Sets the Q flag if the addition overflows. (Overflow cannot occur during the multiplications or the subtraction.) ``` c int32_t __smlsdx(int16x2_t, int16x2_t, int32_t); ``` Performs two 16-bit signed multiplications. The product of the high halfword of the first operand and the low halfword of the second operand is subtracted from the product of the low halfword of the first operand and the high halfword of the second operand, and the difference is added to the third operand. Sets the Q flag if the addition overflows. (Overflow cannot occur during the multiplications or the subtraction.) ``` c int64_t __smlsld(int16x2_t, int16x2_t, int64_t); ``` Perform two 16-bit signed multiplications. Take the difference of the products, subtracting the high-halfword product from the low-halfword product, and add the difference to the third operand. Overflow in the 64-bit addition is not detected. (Overflow cannot occur during the multiplications or the subtraction.) ``` c int64_t __smlsldx(int16x2_t, int16x2_t, int64_t); ``` Perform two 16-bit signed multiplications. The product of the high halfword of the first operand and the low halfword of the second operand is subtracted from the product of the low halfword of the first operand and the high halfword of the second operand, and the difference is added to the third operand. Overflow in the 64-bit addition is not detected. (Overflow cannot occur during the multiplications or the subtraction.) ``` c int32_t __smuad(int16x2_t, int16x2_t); ``` Perform 2x16-bit signed multiplications, adding the products together. Set the Q flag if the addition overflows. ``` c int32_t __smuadx(int16x2_t, int16x2_t); ``` Exchange the halfwords of the second operand (or equivalently, the first operand), perform 2x16-bit signed multiplications, and add the products together. Set the Q flag if the addition overflows. ``` c int32_t __smusd(int16x2_t, int16x2_t); ``` Perform two 16-bit signed multiplications. Take the difference of the products, subtracting the high-halfword product from the low-halfword product. ``` c int32_t __smusdx(int16x2_t, int16x2_t); ``` Perform two 16-bit signed multiplications. The product of the high halfword of the first operand and the low halfword of the second operand is subtracted from the product of the low halfword of the first operand and the high halfword of the second operand. ### Examples Taking the elementwise maximum of two SIMD values each of which consists of four 8-bit signed numbers: ``` c int8x4_t max8x4(int8x4_t x, int8x4_t y) { __ssub8(x, y); return __sel(x, y); } ``` As described in :ref:sec-Parallel-selection, where SIMD values consist of two 16-bit unsigned numbers: ``` c int16x2_t max16x2(int16x2_t x, int16x2_t y) { __usub16(x, y); return __sel(x, y); } ``` Note that even though the result of the subtraction is not used, the compiler must still generate the instruction, because of its side-effect on the GE bits which are tested by the `__sel()` intrinsic. ## Floating-point data-processing intrinsics The intrinsics in this section provide direct access to selected floating-point instructions. They are defined only if the appropriate precision is available in hardware, as indicated by `__ARM_FP` (see [Hardware floating point](#hardware-floating-point)). ``` c double __sqrt(double x); float __sqrtf(float x); ``` The `__sqrt` intrinsics compute the square root of their operand. They have no effect on errno. Negative values produce a default NaN result and possible floating-point exception as described in [ARMARM] (A2.7.7). ``` c double __fma(double x, double y, double z); float __fmaf(float x, float y, float z); ``` The `__fma` intrinsics compute `(x*y)+z`, without intermediate rounding. These intrinsics are available only if `__ARM_FEATURE_FMA` is defined. On a Standard C implementation it should not normally be necessary to use these intrinsics, because the fma functions defined in [C99] (7.12.13) should expand directly to the instructions if available. ``` c float __rintnf (float); double __rintn (double); ``` The `__rintn` intrinsics perform a floating point round to integral, to nearest with ties to even. The `__rintn` intrinsic is available when `__ARM_FEATURE_DIRECTED_ROUNDING` is defined to 1. For other rounding modes like |lsquo| to nearest with ties to away |rsquo| it is strongly recommended that C99 standard functions be used. To achieve a floating point convert to integer, rounding to |lsquo| nearest with ties to even |rsquo| operation, use these rounding functions with a type-cast to integral values. For example: ``` c (int) __rintnf (a); ``` maps to a floating point convert to signed integer, rounding to nearest with ties to even operation. ``` c int32_t __jcvt (double); ``` Converts a double-precision floating-point number to a 32-bit signed integer following the Javascript Convert instruction semantics [[ARMARMv83]](#ARMARMv83). The `__jcvt` intrinsic is available if `__ARM_FEATURE_JCVT` is defined. ``` c float __rint32zf (float); double __rint32z (double); float __rint64zf (float); double __rint64z (double); float __rint32xf (float); double __rint32x (double); float __rint64xf (float); double __rint64x (double); ``` These intrinsics round their floating-point argument to a floating-point value that would be representable in a 32-bit or 64-bit signed integer type. Out-of-Range values are forced to the Most Negative Integer representable in the target size, and an Invalid Operation Floating-Point Exception is generated. The rounding mode can be either the ambient rounding mode (for example `__rint32xf`) or towards zero (for example `__rint32zf`). These instructions are introduced in the Armv8.5-A extensions [[ARMARMv85]](#ARMARMv85) and are available only in the AArch64 execution state. The intrinsics are available when `__ARM_FEATURE_FRINT` is defined. ## Random number generation intrinsics The Random number generation intrinsics provide access to the Random Number instructions introduced in Armv8.5-A. These intrinsics are only defined for the AArch64 execution state and are available when `__ARM_FEATURE_RNG` is defined. ``` c int __rndr (uint64_t *); ``` Stores a 64-bit random number into the object pointed to by the argument and returns zero. If the implementation could not generate a random number within a reasonable period of time the object pointed to by the input is set to zero and a non-zero value is returned. ``` c int __rndrrs (uint64_t *); ``` Reseeds the random number generator. After that stores a 64-bit random number into the object pointed to by the argument and returns zero. If the implementation could not generate a random number within a reasonable period of time the object pointed to by the input is set to zero and a non-zero value is returned. These intrinsics have side-effects on the system beyond their results. Implementations must preserve them even if the results of the intrinsics are unused. To access these intrinsics, `` should be included. ## CRC32 intrinsics CRC32 intrinsics provide direct access to CRC32 instructions CRC32{C}{B, H, W, X} in both Armv8 AArch32 and AArch64 execution states. These intrinsics are available when `__ARM_FEATURE_CRC32` is defined. ``` c uint32_t __crc32b (uint32_t a, uint8_t b); ``` Performs CRC-32 checksum from bytes. ``` c uint32_t __crc32h (uint32_t a, uint16_t b); ``` Performs CRC-32 checksum from half-words. ``` c uint32_t __crc32w (uint32_t a, uint32_t b); ``` Performs CRC-32 checksum from words. ``` c uint32_t __crc32d (uint32_t a, uint64_t b); ``` Performs CRC-32 checksum from double words. ``` c uint32_t __crc32cb (uint32_t a, uint8_t b); ``` Performs CRC-32C checksum from bytes. ``` c uint32_t __crc32ch (uint32_t a, uint16_t b); ``` Performs CRC-32C checksum from half-words. ``` c uint32_t __crc32cw (uint32_t a, uint32_t b); ``` Performs CRC-32C checksum from words. ``` c uint32_t __crc32cd (uint32_t a, uint64_t b); ``` Performs CRC-32C checksum from double words. To access these intrinsics, `` should be included. ## Load/store 64 Byte intrinsics These intrinsics provide direct access to the Armv8.7-A `LD64B`, `ST64B`, `ST64BV` and `ST64BV0` instructions for atomic 64-byte access to device memory. These intrinsics are available when `__ARM_FEATURE_LS64` is defined. The header `` defines these intrinsics, and also the data type `data512_t` that they use. The type `data512_t` is a 64-byte structure type containing a single member `val` which is an array of 8 `uint64_t`, as if declared like this: ``` c typedef struct { uint64_t val[8]; } data512_t; ``` The following intrinsics are defined on this data type. In all cases, the address `addr` must be aligned to a multiple of 64 bytes. ``` c data512_t __arm_ld64b(const void *addr); ``` Loads 64 bytes of data atomically from the address `addr`. The address must be in a memory region that supports 64-byte load/store operations. ``` c void __arm_st64b(void *addr, data512_t value); ``` Stores the 64 bytes in `value` atomically to the address `addr`. The address must be in a memory region that supports 64-byte load/store operations. ``` c uint64_t __arm_st64bv(void *addr, data512_t value); ``` Attempts to store the 64 bytes in `value` atomically to the address `addr`. It returns a 64-bit value from the response of the device written to. ``` c uint64_t __arm_st64bv0(void *addr, data512_t value); ``` Performs the same operation as `__arm_st64bv`, except that the data stored to memory is modified by replacing the low 32 bits of `value.val[0]` with the contents of the `ACCDATA_EL1` system register. The returned value is the same as for `__arm_st64bv`. # Custom Datapath Extension The specification for CDE is in `BETA` state and may change or be extended in the future. The intrinsics in this section provide access to instructions in the Custom Datapath Extension. The `` header should be included before using these intrinsics. The header is available when the `__ARM_FEATURE_CDE` feature macro is defined. The intrinsics are stateless and pure, meaning an implementation is permitted to discard an invocation of an intrinsic whose result is unused without considering side-effects. ## CDE intrinsics The following intrinsics are available when `__ARM_FEATURE_CDE` is defined. These intrinsics use the `coproc` and `imm` compile-time constants to generate the corresponding CDE instructions. The `coproc` argument indicates the CDE coprocessor to use. The range of available coprocessors is indicated by the bitmap `__ARM_FEATURE_CDE_COPROC`, described in [Custom Datapath Extension](#custom-datapath-extension). The `imm` argument must fit within the immediate range of the corresponding CDE instruction. Values for these arguments outside these ranges must be rejected. ``` c uint32_t __arm_cx1(int coproc, uint32_t imm); uint32_t __arm_cx1a(int coproc, uint32_t acc, uint32_t imm); uint32_t __arm_cx2(int coproc, uint32_t n, uint32_t imm); uint32_t __arm_cx2a(int coproc, uint32_t acc, uint32_t n, uint32_t imm); uint32_t __arm_cx3(int coproc, uint32_t n, uint32_t m, uint32_t imm); uint32_t __arm_cx3a(int coproc, uint32_t acc, uint32_t n, uint32_t m, uint32_t imm); uint64_t __arm_cx1d(int coproc, uint32_t imm); uint64_t __arm_cx1da(int coproc, uint64_t acc, uint32_t imm); uint64_t __arm_cx2d(int coproc, uint32_t n, uint32_t imm); uint64_t __arm_cx2da(int coproc, uint64_t acc, uint32_t n, uint32_t imm); uint64_t __arm_cx3d(int coproc, uint32_t n, uint32_t m, uint32_t imm); uint64_t __arm_cx3da(int coproc, uint64_t acc, uint32_t n, uint32_t m, uint32_t imm); ``` The following intrinsics are also available when `__ARM_FEATURE_CDE` is defined, providing access to the CDE instructions that read and write the floating-point registers: ``` c uint32_t __arm_vcx1_u32(int coproc, uint32_t imm); uint32_t __arm_vcx1a_u32(int coproc, uint32_t acc, uint32_t imm); uint32_t __arm_vcx2_u32(int coproc, uint32_t n, uint32_t imm); uint32_t __arm_vcx2a_u32(int coproc, uint32_t acc, uint32_t n, uint32_t imm); uint32_t __arm_vcx3_u32(int coproc, uint32_t n, uint32_t m, uint32_t imm); uint32_t __arm_vcx3a_u32(int coproc, uint32_t acc, uint32_t n, uint32_t m, uint32_t imm); ``` In addition, the following intrinsics can be used to generate the D-register forms of the instructions: ``` c uint64_t __arm_vcx1d_u64(int coproc, uint32_t imm); uint64_t __arm_vcx1da_u64(int coproc, uint64_t acc, uint32_t imm); uint64_t __arm_vcx2d_u64(int coproc, uint64_t m, uint32_t imm); uint64_t __arm_vcx2da_u64(int coproc, uint64_t acc, uint64_t m, uint32_t imm); uint64_t __arm_vcx3d_u64(int coproc, uint64_t n, uint64_t m, uint32_t imm); uint64_t __arm_vcx3da_u64(int coproc, uint64_t acc, uint64_t n, uint64_t m, uint32_t imm); ``` The above intrinsics use the `uint32_t` and `uint64_t` types as general container types. The following intrinsics can be used to generate CDE instructions that use the MVE Q registers. ``` c uint8x16_t __arm_vcx1q_u8 (int coproc, uint32_t imm); T __arm_vcx1qa(int coproc, T acc, uint32_t imm); T __arm_vcx2q(int coproc, T n, uint32_t imm); uint8x16_t __arm_vcx2q_u8(int coproc, T n, uint32_t imm); T __arm_vcx2qa(int coproc, T acc, U n, uint32_t imm); T __arm_vcx3q(int coproc, T n, U m, uint32_t imm); uint8x16_t __arm_vcx3q_u8(int coproc, T n, U m, uint32_t imm); T __arm_vcx3qa(int coproc, T acc, U n, V m, uint32_t imm); T __arm_vcx1q_m(int coproc, T inactive, uint32_t imm, mve_pred16_t p); T __arm_vcx2q_m(int coproc, T inactive, U n, uint32_t imm, mve_pred16_t p); T __arm_vcx3q_m(int coproc, T inactive, U n, V m, uint32_t imm, mve_pred16_t p); T __arm_vcx1qa_m(int coproc, T acc, uint32_t imm, mve_pred16_t p); T __arm_vcx2qa_m(int coproc, T acc, U n, uint32_t imm, mve_pred16_t p); T __arm_vcx3qa_m(int coproc, T acc, U n, V m, uint32_t imm, mve_pred16_t p); ``` These intrinsics are polymorphic in the `T`, `U` and `V` types, which must be of size 128 bits. The `__arm_vcx1q_u8`, `__arm_vcx2q_u8` and `__arm_vcx3q_u8` intrinsics return a container vector of 16 bytes that can be reinterpreted to other vector types as needed using the intrinsics below: ``` c uint16x8_t __arm_vreinterpretq_u16_u8 (uint8x16_t in); int16x8_t __arm_vreinterpretq_s16_u8 (uint8x16_t in); uint32x4_t __arm_vreinterpretq_u32_u8 (uint8x16_t in); int32x4_t __arm_vreinterpretq_s32_u8 (uint8x16_t in); uint64x2_t __arm_vreinterpretq_u64_u8 (uint8x16_t in); int64x2_t __arm_vreinterpretq_s64_u8 (uint8x16_t in); float16x8_t __arm_vreinterpretq_f16_u8 (uint8x16_t in); float32x4_t __arm_vreinterpretq_f32_u8 (uint8x16_t in); float64x2_t __arm_vreinterpretq_f64_u8 (uint8x16_t in); ``` The parameter `inactive` can be set to an uninitialized (don't care) value using the MVE `vuninitializedq` family of intrinsics. # Memory tagging intrinsics The intrinsics in this section provide access to the Memory Tagging Extension (MTE) introduced with the Armv8.5-A [[ARMARMv85]](#ARMARMv85) architecture. The `` header should be included before using these intrinsics. These intrinsics are expected to be used in system code, including freestanding environments. As such, implementations must guarantee that no new linking dependencies to runtime support libraries will occur when these intrinsics are used. ## Memory tagging Memory tagging is a lightweight, probabilistic version of a lock and key system where one of a limited set of lock values can be associated with the memory locations forming part of an allocation, and the equivalent key is stored in unused high bits of addresses used as references to that allocation. On each use of a reference the key is checked to make sure that it matches with the lock before an access is made. When allocating memory, programmers must assign a lock to that section of memory. When freeing an allocation, programmers must change the lock value so that further referencing using the previous key has a reasonable probability of failure. The intrinsics specified below support creation, storage, and retrieval of the lock values, leaving software to select and set the values on allocation and deallocation. The intrinsics are expected to help protect heap allocations. The lock is referred in the text below as `allocation tag` and the key as `logical address tag` (or in short `logical tag`). ## Terms and implementation details The memory system is extended with a new physical address space containing an allocation tag for each 16-byte granule of memory in the existing data physical address space. All loads and stores to memory must pass a valid logical address tag as part of the reference. However, SP- and PC-relative addresses are not checked. The logical tag is held in the upper bits of the reference. There are 16 available logical tags that can be used. ## MTE intrinsics These intrinsics are available when `__ARM_FEATURE_MEMORY_TAGGING` is defined. Type T below can be any type. Where the function return type is specified as T, the return type is determined from the input argument which must be also be specified as of type T. If the input argument T has qualifiers `const` or `volatile`, the return type T will also have the `const` or `volatile` qualifier. ``` c T* __arm_mte_create_random_tag(T* src, uint64_t mask); ``` This intrinsic returns a pointer containing a randomly created logical address tag. The first argument is a pointer `src` containing an address. The second argument is a `mask`, where the lower 16 bits specify logical tags which must be excluded from consideration. The intrinsic returns a pointer which is a copy of the input address but also contains a randomly created logical tag (in the upper bits), that excludes any logical tags specified by the `mask`. A `mask` of zero excludes no tags. ``` c T* __arm_mte_increment_tag(T* src, unsigned offset); ``` This intrinsic returns a pointer which is a copy of the input pointer `src` but with the logical address tag part offset by a specified offset value. The first argument is a pointer `src` containing an address and a logical tag. The second argument is an offset which must be a compile time constant value in the range [0,15]. The intrinsic adds `offset` to the logical tag part of `src` returning a pointer with the incremented logical tag. If adding the offset increments the logical tag beyond the valid 16 tags, the value is wrapped around. ``` c uint64_t __arm_mte_exclude_tag(T* src, uint64_t excluded); ``` This intrinsic adds a logical tag to the set of excluded logical tags. The first argument is a pointer `src` containing an address and a logical tag. The second argument `excluded` is a mask where the lower 16 bits specify logical tags which are in current excluded set. The intrinsic adds the logical tag of `src` to the set specified by `excluded` and returns the new excluded tag set. ``` c void __arm_mte_set_tag(T* tag_address); ``` This intrinsic stores an allocation tag, computed from the logical tag, to the tag memory thereby setting the allocation tag for the 16-byte granule of memory. The argument is a pointer `tag_address` containing a logical tag and an address. The address must be 16-byte aligned. The type of the pointer is ignored (i.e. allocation tag is set only for a single granule even if the pointer points to a type that is greater than 16 bytes). These intrinsics generate an unchecked access to memory. ``` c T* __arm_mte_get_tag(T* address); ``` This intrinsic loads the allocation tag from tag memory and returns the corresponding logical tag as part of the returned pointer value. The argument is a pointer `address` containing an address from which allocation tag memory is read. The pointer `address` need not be 16-byte aligned as it applies to the 16-byte naturally aligned granule containing the un-aligned pointer. The return value is a pointer whose address part comes from `address` and the logical tag value is the value computed from the allocation tag that was read from tag memory. ``` c ptrdiff_t __arm_mte_ptrdiff(T* a, T* b); ``` The intrinsic calculates the difference between the address parts of the two pointers, ignoring the tags. The return value is the sign-extended result of the computation. The tag bits in the input pointers are ignored for this operation. # State management The specification for SME is in [**Beta** state](#current-status-and-anticipated-changes) and may change or be extended in the future. ## Introduction ACLE often uses normal C and C++ objects to represent architectural state. These objects are passed to intrinsics and returned from intrinsics in the same way as they would be for a normal function. For example, ACLE defines an `svbool_t` type to represent the contents of an SVE predicate register. SVE intrinsics that read a predicate register have an `svbool_t` argument for that register. SVE intrinsics that write to a predicate register have an `svbool_t` return type for that register. SVE provides 16 predicate registers, but this number is not exposed to C and C++ code. Instead, the program can have as many `svbool_t` objects as it needs, and it is the compiler's responsibility to manage the register allocation. However, there are some pieces of architectural state for which this approach is not suitable. For example, [SME's ZA](#za-storage) is a single piece of storage: there are not multiple ZAs, and so it does not make sense for a C or C++ function to have multiple ZA objects. It would also be inefficient to copy state from one ZA object to another. ACLE models this kind of architectural state using [keyword attributes](#keyword-attributes) rather than types and objects. The main purpose of these keyword attributes is to establish the following binary choices for a given piece of architectural state S: 1. A function with a given type either shares S with its caller, or it does not. 2. A given function definition either uses S internally, or it does not. A function definition that shares S with its caller also (implicitly) uses S internally. A function definition that uses S internally but does not share S with its caller is said to create a “new scope” for S. ACLE uses strings to identify each piece of state that is managed in this way. The strings are listed in the table below. | **String** | **State** | **State macro** | **Feature macro** | | ---------- | ------------------ | ----------------- | -------------------- | | `"za"` | SME's ZA storage | `__ARM_STATE_ZA` | `__ARM_FEATURE_SME` | | `"zt0"` | SME2's ZT0 | `__ARM_STATE_ZT0` | `__ARM_FEATURE_SME2` | For each string, there are two associated macros: * a so-called “state macro” that compilers predefine if they recognize the string * a so-called “feature macro” that compilers predefine if they can compile functions that use the state A compiler that predefines the feature macro must also predefine the state macro. For example, `__ARM_STATE_ZA` allows declarations of functions that share ZA. `__ARM_FEATURE_SME` allows function definitions to use ZA internally. The strings are case-sensitive. For example, `"za"` cannot be written `"ZA"`. ## Ways of sharing state ACLE identifies several different ways in which a callee can share state with its caller. Each one has an associated [keyword attribute](#keyword-attributes): * `__arm_in`: the callee takes the state as input and returns with the state unchanged. This is similar to a const reference in C++. * `__arm_out`: the callee ignores the incoming state and returns new state. This is similar to a function return value. * `__arm_inout`: the callee takes the state as input and returns new state. This is similar to a non-const reference in C++. * `__arm_preserves`: the callee does not read the incoming state and returns with the state unchanged. Each keyword attribute takes a comma-separated list of state strings as an argument. The list must be non-empty. For example: ``` c void f() __arm_inout("za") __arm_preserves("zt0"); ``` says that `f` uses ZA to receive data from callers and to pass data back to callers. `f` also promises to preserve the contents of ZT0. A program is [ill-formed](#ill-formed) if a function type has two attributes that specify different behavior for the same piece of state. For example, a program is ill-formed if a function type has both `__arm_in("za")` and `__arm_out("za")`, or both `__arm_in("za")` and `__arm_inout("za")`. The same information may be specified multiple times. For example: ``` c void f() __arm_in("za", "za") __arm_in("za"); ``` is well-formed. Two function types are incompatible if they handle a piece of architectural state differently. For example: ``` c void f1() __arm_in("za"); void f2() __arm_out("za"); void f3() __arm_inout("za"); void f4() __arm_preserves("za"); void f5(); void (*ptr1)() __arm_in("za"); void (*ptr2)() __arm_out("za"); void (*ptr3)() __arm_inout("za"); void (*ptr4)() __arm_preserves("za"); void (*ptr5)(); void test() { ptr1 = f1; // OK ptr2 = f1; // Invalid ptr3 = f1; // Invalid ptr4 = f1; // Invalid ptr5 = f1; // Invalid ptr1 = f2; // Invalid ptr2 = f2; // OK ptr3 = f2; // Invalid ptr4 = f2; // Invalid ptr5 = f2; // Invalid ptr1 = f3; // Invalid ptr2 = f3; // Invalid ptr3 = f3; // OK ptr4 = f3; // Invalid ptr5 = f3; // Invalid ptr1 = f4; // Invalid ptr2 = f4; // Invalid ptr3 = f4; // Invalid ptr4 = f4; // OK ptr5 = f4; // Invalid ptr1 = f5; // Invalid ptr2 = f5; // Invalid ptr3 = f5; // Invalid ptr4 = f5; // Invalid ptr5 = f5; // OK } ``` `__arm_in` and `__arm_preserves` both guarantee that a function leaves the contents of the state unchanged on return. Functions are not [ill-formed](#ill-formed) if they write to such state, but they must ensure that the cumulative effect of such writes is to leave the state unchanged. A program is [ill-formed](#ill-formed) if a function that does not [use state](#uses-state) S contains a call to a function that shares S with its caller. This is conceptually similar to an undefined variable in C. For example: ``` c void callee() __arm_inout("za"); void caller() { callee(); // Ill-formed, caller does not use ZA } ``` If a C or C++ function F [uses state](#uses-state) S internally and calls a function F2 that does not share S with its callers, the call to F2 has no effect on F's S state. The compiler must ensure this by [restoring the old contents of S](#za-implementation-notes) after the call to F2, if such a restoration is necessary. For example: ``` c void za_callee() __arm_inout("za"); void za_caller() __arm_inout("za") { za_callee(); printf("Here\n"); // Does not change za_caller's ZA state za_callee(); } ``` ## Mapping to the Procedure Call Standard [[AAPCS64]](#AAPCS64) classifies functions as having one of the following interfaces: * a “private-ZA” interface * a “shared-ZA” interface If a C or C++ function F forms part of the object code's ABI, that object code function has a shared-ZA interface if and only if at least one of the following is true: * F shares ZA with its caller * F shares ZT0 with its caller All other functions have a private-ZA interface. ## Function definitions The [keyword attribute](#keyword-attributes) `__arm_new(...)` applies to function definitions. It specifies that the function creates a [new scope](#new-state-scope) for the given state. `...` is a comma-separated list of [state strings](#state-strings). The list must be non-empty. Each piece of state specified by `__arm_new` is zero-initialized. This attribute does not change a function's binary interface. If the function forms part of the object code's ABI, that object code function has the same interface as it would have had without `__arm_new`. A program is [ill-formed](#ill-formed) if a function definition F uses `__arm_new` for some state that F also [shares](#shares-state) with its caller. For example: ``` c __arm_new("za") void f1() __arm_in("za") { ... } // Invalid __arm_new("za") void f2() __arm_out("za") { ... } // Invalid __arm_new("za") void f3() __arm_inout("za") { ... } // Invalid __arm_new("za") void f4() __arm_inout("zt0") { ... } // OK __arm_new("zt0") void f5() __arm_inout("za") { ... } // OK ``` ## Inline assembly Some ACLE implementations might support the GNU inline asm extension. For implementations that do, suppose that an inline asm occurs in a function F that [uses state](#uses-state) S. There are then two possibilities: * S is not an input to the asm and S is not an output from the asm. The contents of S immediately after executing the asm's instructions are the same as the contents of S immediately before executing the instructions. This is the default assumption. * S might be an input to the asm, might be an output from the asm, and might be changed by the asm's instructions. This is indicated by adding S's string to the asm's clobber list. For example, if an asm's clobber list includes `"za"`, ZA might be an input to the asm, an output from the asm, or something that the asm changes. If instead the inline asm occurs in a function that does not [use state](#uses-state) S, the two possibilities are: * S is not an input to the asm and S is not an output from the asm. The contents of S immediately after executing the asm's instructions are the same as the contents of S immediately before executing the instructions. This is the default assumption. * S is not an input to the asm and S is not an output from the asm. However, the contents of S after executing the asm's instructions might be different from the contents of S before executing the instructions. This is indicated by adding S's string to the asm's clobber list. If an asm takes this option for state that is controlled by PSTATE.ZA, the asm itself is responsible for handling the [[AAPCS64]](#AAPCS64) lazy save scheme. [[AAPCS64]](#AAPCS64) defines three possible states for ZA: “off”, “dormant” or “active”. These states describe the values of two things: * the PSTATE.ZA bit * the TPIDR2_EL0 register ZA is guaranteed to be active on entry to an inline asm A in a function F if at least one of the following is true: * F [uses `"za"`](#uses-state) and A's clobber list includes `"za"`. * F [uses `"zt0"`](#uses-state) and A's clobber list includes `"zt0"`. Otherwise, ZA can be in any state on entry to A if at least one of the following is true: * F [uses](#uses-state) `"za"` * F [uses](#uses-state) `"zt0"` Otherwise, ZA can be off or dormant on entry to A, as for what AAPCS64 calls “private-ZA” functions. If ZA is active on entry to A then A's instructions must ensure that ZA is also active when the asm finishes. Similarly, if ZA is off on entry to A then A's instructions must ensure that ZA is off when the asm finishes. If ZA is dormant on entry to A and A's clobber list does not include `"za"`, A's instructions must ensure that ZA is dormant when the asm finishes. Otherwise, if ZA is dormant on entry to A and A's clobber list includes `"za"`, A's instructions can leave ZA unchanged or in the off state (A's choice). In the latter case, A's instructions must commit the lazy save that was pending on entry to A. The table below summarizes the possible ZA states on entry to an inline asm A in a function F. It also specifies what the state is required to be when A finishes; it is the asm's responsibility to ensure this. Since PSTATE.ZA controls both ZA and ZT0, the rules depend on ZT0 as well as ZA. | **ZA state before A** | **ZA state after A** | **Possible if…** | | --------------------- | -------------------- | -------------------------------------- | | off | off | F's uses and A's clobbers are disjoint | | dormant | dormant | " " " | | dormant | off | " " ", and A clobbers `"za"` | | active | active | F uses `"za"` and/or `"zt0"` | The [`__ARM_STATE` macros](#state-strings) indicate whether a compiler is guaranteed to support a particular clobber string. For example, the following code is a safe way to indicate that an asm might commit a lazy ZA save: ``` c // Function foo doesn't use ZA or ZT0. void foo() { ... asm volatile("bl something" ::: ...call-clobbered registers... #ifdef __ARM_STATE_ZA , "za" #endif ); ... } ``` ## Implementation notes A piece of state S can be said to be “live” at a point P during the execution of a function F if: * F [uses](#uses-state) S; and * a random, exogenous change to S at P could change the behavior of the program. If S is live before a call from F to a function F2 that does not share S with its caller, the compiler must arrange for S to be preserved around the call to F2. One way to do this is to save S before the call and restore it afterwards. However, if S is ZA and F2 is a private-ZA function, the compiler can instead make use of the lazy-save scheme described in [[AAPCS64]](#AAPCS64). For example, the code below shows a function that uses ZA and ZT0 internally. The comments describe when ZA should be saved and restored: ``` c void f_shares_zt0() __arm_inout("zt0"); void f_shares_za() __arm_inout("za"); void f_private(); void setup_za() __arm_out("za"); void use_za() __arm_in("za"); __arm_new("za", "zt0") void test() { f_private(); // ZA is not live, no save necessary setup_za(); // ZA is live after this call f_shares_zt0(); // The compiler should save and restore ZA // around the call ("caller-save") f_shares_za(); // ZA is live before and after this call f_private(); // The compiler should preserve ZA across the call // It can use the lazy-save mechanism use_za(); // ZA is no longer live after this call f_private(); // ZA is not live, no save necessary } ``` ZT0 cannot be saved lazily, so if ZT0 is live before a call to a function that does not share ZT0, the compiler must save and restore ZT0 around the call. For example: ``` c void setup_zt0() __arm_out("zt0"); void use_zt0() __arm_in("zt0"); void f_private(); __arm_new("zt0") void test() { f_private(); // ZT0 is not live, no save necessary setup_zt0(); // ZT0 is live after this call f_private(); // The compiler should save and restore ZT0 // around the call ("caller-save") use_zt0(); // ZT0 is no longer live after this call f_private(); // ZT0 is not live, no save necessary } ``` # System register access ## Special register intrinsics Intrinsics are provided to read and write system and coprocessor registers, collectively referred to as special register. ``` c uint32_t __arm_rsr(const char *special_register); ``` Reads a 32-bit system register. ``` c uint64_t __arm_rsr64(const char *special_register); ``` Reads a 64-bit system register. ``` c __uint128_t __arm_rsr128(const char *special_register); ``` Reads a 128-bit system register. Only available if `__ARM_FEATURE_SYSREG128` is defined to 1. ``` c void* __arm_rsrp(const char *special_register); ``` Reads a system register containing an address. ``` c float __arm_rsrf(const char *special_register); ``` Reads a 32-bit coprocessor register containing a floating point value. ``` c double __arm_rsrf64(const char *special_register); ``` Reads a 64-bit coprocessor register containing a floating point value. ``` c void __arm_wsr(const char *special_register, uint32_t value); ``` Writes a 32-bit system register. ``` c void __arm_wsr64(const char *special_register, uint64_t value); ``` Writes a 64-bit system register. ``` c void __arm_wsr128(const char *special_register, __uint128_t value); ``` Writes a 128-bit system register. Only available if `__ARM_FEATURE_SYSREG128` is defined to 1. ``` c void __arm_wsrp(const char *special_register, const void *value); ``` Writes a system register containing an address. ``` c void __arm_wsrf(const char *special_register, float value); ``` Writes a floating point value to a 32-bit coprocessor register. ``` c void __arm_wsrf64(const char *special_register, double value); ``` Writes a floating point value to a 64-bit coprocessor register. ## Special register designations The `special_register` parameter must be a compile time string literal. This means that the implementation can determine the register being accessed at compile-time and produce the correct instruction without having to resort to self-modifying code. All register specifiers are case-insensitive (so "apsr" is equivalent to "APSR"). The string literal should have one of the forms described below. ### AArch32 32-bit coprocessor register When specifying a 32-bit coprocessor register to `__arm_rsr`, `__arm_rsrp`, `__arm_rsrf`, `__arm_wsr`, `__arm_wsrp`, or `__arm_wsrf`: ``` c cp::c:c: ``` Or (equivalently): ``` c p::c:c: ``` Where: * `` is a decimal integer in the range `[0, 15]` * ``, `` are decimal integers in the range `[0, 7]` * ``, `` are decimal integers in the range `[0, 15]`. The values of the register specifiers will be as described in [[ARMARM]](#ARMARM) or the Technical Reference Manual (TRM) for the specific processor. So to read MIDR: ``` c unsigned int midr = __arm_rsr("cp15:0:c0:c0:0"); ``` ACLE does not specify predefined strings for the system coprocessor register names documented in the Arm Architecture Reference Manual (for example “ MIDR ”). ### AArch32 32-bit system register When specifying a 32-bit system register to `__arm_rsr`, `__arm_rsrp`, `__arm_wsr`, or `__arm_wsrp`, one of: * The values accepted in the `spec_reg` field of the MRS instruction [[ARMARM]](#ARMARM) (B6.1.5), for example CPSR. * The values accepted in the `spec_reg` field of the MSR (immediate) instruction [[ARMARM]](#ARMARM) (B6.1.6). * The values accepted in the `spec_reg` field of the VMRS instruction [[ARMARM]](#ARMARM) (B6.1.14), for example FPSID. * The values accepted in the `spec_reg` field of the VMSR instruction [[ARMARM]](#ARMARM) (B6.1.15), for example FPSCR. * The values accepted in the `spec_reg` field of the MSR and MRS instructions with virtualization extensions [[ARMARM]](#ARMARM) (B1.7), for example `ELR_Hyp`. * The values specified in Special register encodings used in Armv7-M system instructions. [[ARMv7M]](#ARMv7M) (B5.1.1), for example PRIMASK. ### AArch32 64-bit coprocessor register When specifying a 64-bit coprocessor register to `__arm_rsr64`, `__arm_rsrf64`, `__arm_wsr64`, or `__arm_wsrf64` ``` c cp::c ``` Or (equivalently): ``` c p::c ``` Where: * `` is a decimal integer in the range `[0, 15]` * `` is a decimal integer in the range `[0, 7]` * `` is a decimal integer in the range `[0, 15]` ### AArch64 system register When specifying a system register to `__arm_rsr`, `__arm_rsr64`, `__arm_rsr128`, `__arm_rsrp`, `__arm_wsr`, `__arm_wsr64`,`__arm_wsr128` or `__arm_wsrp`: ``` c "o0:op1:CRn:CRm:op2" ``` Where: * `` is a decimal integer in the range `[0, 1]` * ``, `` are decimal integers in the range `[0, 7]` * ``, `` are decimal integers in the range `[0, 15]` ### AArch64 processor state field When specifying a processor state field to `__arm_rsr`, `__arm_rsp`, `__arm_wsr`, or `__arm_wsrp`, one of the values accepted in the pstatefield of the MSR (immediate) instruction [[ARMARMv8]](#ARMARMv8) (C5.6.130). ## Coprocessor Intrinsics ### AArch32 coprocessor intrinsics In the intrinsics below `coproc`, `opc1`, `opc2`, `CRn` and `CRd` are all compile time integer constants with appropriate values as defined by the coprocessor for the intended architecture. The argument order for all intrinsics is the same as the operand order for the instruction as described in the Arm Architecture Reference Manual, with the exception of `MRC`/ `MRC2`/ `MRRC`/`MRRC2` which omit the Arm register arguments and instead returns a value and `MCRR`/`MCRR2` which accepts a single 64 bit unsigned integer instead of two 32-bit unsigned integers. ### AArch32 Data-processing coprocessor intrinsics Intrinsics are provided to create coprocessor data-processing instructions as follows: | **Intrinsics** | **Equivalent Instruction** | | ----------------------------------------------------- | -------------------------------------- | | void __arm_cdp(coproc, opc1, CRd, CRn, CRm, opc2) | CDP coproc, opc1, CRd, CRn, CRm, opc2 | | void __arm_cdp2(coproc, opc1, CRd, CRn, CRm, opc2) | CDP2 coproc, opc1, CRd, CRn, CRm, opc2 | #### AArch32 Memory coprocessor transfer intrinsics Intrinsics are provided to create coprocessor memory transfer instructions as follows: | **Intrinsics** | **Equivalent Instruction** | | ------------------------------------------------ | -------------------------- | | void __arm_ldc(coproc, CRd, const void* p) | LDC coproc, CRd, [...] | | void __arm_ldcl(coproc, CRd, const void* p) | LDCL coproc, CRd, [...] | | void __arm_ldc2(coproc, CRd, const void* p) | LDC2 coproc, CRd, [...] | | void __arm_ldc2l(coproc, CRd, const void* p) | LDC2L coproc, CRd, [...] | | void __arm_stc(coproc, CRd, void* p) | STC coproc, CRd, [...] | | void __arm_stcl(coproc, CRd, void* p) | STCL coproc, CRd, [...] | | void __arm_stc2(coproc, CRd, void* p) | STC2 coproc, CRd, [...] | | void __arm_stc2l(coproc, CRd, void* p) | STC2L coproc, CRd, [...] | ### AArch32 Integer to coprocessor transfer intrinsics Intrinsics are provided to map to coprocessor to core register transfer instructions as follows: | **Intrinsics** | **Equivalent Instruction** | | ----------------------------------------------------------------- | ------------------------------------- | | void __arm_mcr(coproc, opc1, uint32_t value, CRn, CRm, opc2) | MCR coproc, opc1, Rt, CRn, CRm, opc2 | | void __arm_mcr2(coproc, opc1, uint32_t value, CRn, CRm, opc2) | MCR2 coproc, opc1, Rt, CRn, CRm, opc2 | | uint32_t __arm_mrc(coproc, opc1, CRn, CRm, opc2) | MRC coproc, opc1, Rt, CRn, CRm, opc2 | | uint32_t __arm_mrc2(coproc, opc1, CRn, CRm, opc2) | MRC2 coproc, opc1, Rt, CRn, CRm, opc2 | | void __arm_mcrr(coproc, opc1, uint64_t value, CRm) | MCRR coproc, opc1, Rt, Rt2, CRm | | void __arm_mcrr2(coproc, opc1, uint64_t value, CRm) | MCRR2 coproc, opc1, Rt, Rt2, CRm | | uint64_t __arm_mrrc(coproc, opc1, CRm) | MRRC coproc, opc1, Rt, Rt2, CRm | | uint64_t __arm_mrrc2(coproc, opc1, CRm) | MRRC2 coproc, opc1, Rt, Rt2, CRm | The intrinsics `__arm_mcrr`/`__arm_mcrr2` accept a single unsigned 64-bit integer value instead of two 32-bit integers. The low half of the value goes in register `Rt` and the high half goes in `Rt2`. Likewise for `__arm_mrrc`/`__arm_mrrc2` which return an unsigned 64-bit integer. ## Unspecified behavior ACLE does not specify how the implementation should behave in the following cases: * When merging multiple reads/writes of the same register. * When writing to a read-only register, or a register that is undefined on the architecture being compiled for. * When reading or writing to a register which the implementation models by some other means (this covers – but is not limited to – reading/writing cp10 and cp11 registers when VFP is enabled, and reading/writing the CPSR). * When reading or writing a register using one of these intrinsics with an inappropriate type for the value being read or written to. * When writing to a coprocessor register that carries out a "System operation". * When using a register specifier which doesn't apply to the targetted architecture. # Instruction generation ## Instruction generation, arranged by instruction The following table indicates how instructions may be generated by intrinsics, and/or C code. The table includes integer data processing and certain system instructions. Compilers are encouraged to use opportunities to combine instructions, or to use shifted/rotated operands where available. In general, intrinsics are not provided for accumulating variants of instructions in cases where the accumulation is a simple addition (or subtraction) following the instruction. The table indicates which architectures the instruction is supported on, as follows: Architecture 8 means Armv8-A AArch32 and AArch64, 8-32 means Armv8-AArch32 only. 8-64 means Armv8-AArch64 only. Architecture 7 means Armv7-A and Armv7-R. In the sequence of Arm architectures { 5, 5TE, 6, 6T2, 7 } each architecture includes its predecessor instruction set. In the sequence of Thumb-only architectures { 6-M, 7-M, 7E-M } each architecture includes its predecessor instruction set. 7MP are the Armv7 architectures that implement the Multiprocessing Extensions. | **Instruction** | **Flags** | **Arch.** | **Intrinsic or C code** | | --------------- | --------- | ------------- | ----------------------------------------------------- | | BKPT | | 5 | none | | BFC | | 6T2, 7-M | C | | BFI | | 6T2, 7-M | C | | CLZ | | 5 | `__clz`, `__builtin_clz` | | DBG | | 7, 7-M | `__dbg` | | DMB | | 8,7, 6-M | `__dmb` | | DSB | | 8, 7, 6-M | `__dsb` | | FRINT32Z | | 8-64 | `__rint32zf`, `__rint32z` | | FRINT64Z | | 8-64 | `__rint64zf`, `__rint64z` | | FRINT32X | | 8-64 | `__rint32xf`, `__rint32x` | | FRINT64X | | 8-64 | `__rint64xf`, `__rint64x` | | ISB | | 8, 7, 6-M | `__isb` | | LDREX | | 6, 7-M | `__sync_xxx` | | LDRT | | all | none | | MCR/MRC | | all | see [System register access](#system-register-access) | | MSR/MRS | | 6-M | see [System register access](#system-register-access) | | MSRR/MRRS | | 8-64 | see [System register access](#system-register-access) | | PKHBT | | 6 | C | | PKHTB | | 6 | C | | PLD | | 8-32,5TE, 7-M | `__pld` | | PLDW | | 7-MP | `__pldx` | | PLI | | 8-32,7 | `__pli` | | QADD | Q | 5E, 7E-M | `__qadd` | | QADD16 | | 6, 7E-M | `__qadd16` | | QADD8 | | 6, 7E-M | `__qadd8` | | QASX | | 6, 7E-M | `__qasx` | | QDADD | Q | 5E, 7E-M | `__qadd(__qdbl)` | | QDSUB | Q | 5E, 7E-M | `__qsub(__qdbl)` | | QSAX | | 6, 7E-M | `__qsax` | | QSUB | Q | 5E, 7E-M | `__qsub` | | QSUB16 | | 6, 7E-M | `__qsub16` | | QSUB8 | | 6, 7E-M | `__qsub8` | | RBIT | | 8,6T2, 7-M | `__rbit`, `__builtin_rbit` | | REV | | 8,6, 6-M | `__rev`, `__builtin_bswap32` | | REV16 | | 8,6, 6-M | `__rev16` | | REVSH | | 6, 6-M | `__revsh` | | ROR | | all | `__ror` | | SADD16 | GE | 6, 7E-M | `__sadd16` | | SADD8 | GE | 6, 7E-M | `__sadd8` | | SASX | GE | 6, 7E-M | `__sasx` | | SBFX | | 8,6T2, 7-M | C | | SDIV | | 7-M+ | C | | SEL | (GE) | 6, 7E-M | `__sel` | | SETEND | | 6 | n/a | | SEV | | 8,6K,6-M,7-M | `__sev` | | SHADD16 | | 6, 7E-M | `__shadd16` | | SHADD8 | | 6, 7E-M | `__shadd8` | | SHASX | | 6, 7E-M | `__shasx` | | SHSAX | | 6, 7E-M | `__shsax` | | SHSUB16 | | 6, 7E-M | `__shsub16` | | SHSUB8 | | 6, 7E-M | `__shsub8` | | SMC | | 8,6Z, T2 | none | | SMI | | 6Z, T2 | none | | SMLABB | Q | 5E, 7E-M | `__smlabb` | | SMLABT | Q | 5E, 7E-M | `__smlabt` | | SMLAD | Q | 6, 7E-M | `__smlad` | | SMLADX | Q | 6, 7E-M | `__smladx` | | SMLAL | | all, 7-M | C | | SMLALBB | | 5E, 7E-M | `__smulbb` and C | | SMLALBT | | 5E, 7E-M | `__smulbt` and C | | SMLALTB | | 5E, 7E-M | `__smultb` and C | | SMLALTT | | 5E, 7E-M | `__smultt` and C | | SMLALD | | 6, 7E-M | `__smlald` | | SMLALDX | | 6, 7E-M | `__smlaldx` | | SMLATB | Q | 5E, 7E-M | `__smlatb` | | SMLATT | Q | 5E, 7E-M | `__smlatt` | | SMLAWB | Q | 5E, 7E-M | `__smlawb` | | SMLAWT | Q | 5E, 7E-M | `__smlawt` | | SMLSD | Q | 6, 7E-M | `__smlsd` | | SMLSDX | Q | 6, 7E-M | `__smlsdx` | | SMLSLD | | 6, 7E-M | `__smlsld` | | SMLSLDX | | 6, 7E-M | `__smlsldx` | | SMMLA | | 6, 7E-M | C | | SMMLAR | | 6, 7E-M | C | | SMMLS | | 6, 7E-M | C | | SMMLSR | | 6, 7E-M | C | | SMMUL | | 6, 7E-M | C | | SMMULR | | 6, 7E-M | C | | SMUAD | Q | 6, 7E-M | `__smuad` | | SMUADX | Q | 6, 7E-M | `__smuadx` | | SMULBB | | 5E, 7E-M | `__smulbb;` C | | SMULBT | | 5E, 7E-M | `__smulbt` ; C | | SMULTB | | 5E, 7E-M | `__smultb;` C | | SMULTT | | 5E, 7E-M | `__smultt;` C | | SMULL | | all, 7-M | C | | SMULWB | | 5E, 7E-M | `__smulwb;` C | | SMULWT | | 5E, 7E-M | `__smulwt;` C | | SMUSD | | 6, 7E-M | `__smusd` | | SMUSDX | | 6, 7E-M | `__smusd` | | SSAT | Q | 6, 7-M | `__ssat` | | SSAT16 | Q | 6, 7E-M | `__ssat16` | | SSAX | GE | 6, 7E-M | `__ssax` | | SSUB16 | GE | 6, 7E-M | `__ssub16` | | SSUB8 | GE | 6, 7E-M | `__ssub8` | | STREX | | 6, 7-M | `__sync_xxx` | | STRT | | all | none | | SVC | | all | none | | SWP | | A32 only | `__swp` [deprecated; see [Swap](#swap)] | | SXTAB | | 6, 7E-M | `(int8_t)x` + a | | SXTAB16 | | 6, 7E-M | `__sxtab16` | | SXTAH | | 6, 7E-M | `(int16_t)x` + a | | SXTB | | 8,6, 6-M | `(int8_t)x` | | SXTB16 | | 6, 7E-M | `__sxtb16` | | SXTH | | 8,6, 6-M | `(int16_t)x` | | UADD16 | GE | 6, 7E-M | `__uadd16` | | UADD8 | GE | 6, 7E-M | `__uadd8` | | UASX | GE | 6, 7E-M | `__uasx` | | UBFX | | 8,6T2, 7-M | C | | UDIV | | 7-M+ | C | | UHADD16 | | 6, 7E-M | `__uhadd16` | | UHADD8 | | 6, 7E-M | `__uhadd8` | | UHASX | | 6, 7E-M | `__uhasx` | | UHSAX | | 6, 7E-M | `__uhsax` | | UHSUB16 | | 6, 7E-M | `__uhsub16` | | UHSUB8 | | 6, 7E-M | `__uhsub8` | | UMAAL | | 6, 7E-M | C | | UMLAL | | all, 7-M | `acc += (uint64_t)x * y` | | UMULL | | all, 7-M | C | | UQADD16 | | 6, 7E-M | `__uqadd16` | | UQADD8 | | 6, 7E-M | `__uqadd8` | | UQASX | | 6, 7E-M | `__uqasx` | | UQSAX | | 6, 7E-M | `__uqsax` | | UQSUB16 | | 6, 7E-M | `__uqsub16` | | UQSUB8 | | 6, 7E-M | `__uqsub8` | | USAD8 | | 6, 7E-M | `__usad8` | | USADA8 | | 6, 7E-M | `__usad8 + acc` | | USAT | Q | 6, 7-M | `__usat` | | USAT16 | Q | 6, 7E-M | `__usat16` | | USAX | | 6, 7E-M | `__usax` | | USUB16 | | 6, 7E-M | `__usub16` | | USUB8 | | 6, 7E-M | `__usub8` | | UXTAB | | 6, 7E-M | `(uint8_t)x + i` | | UXTAB16 | | 6, 7E-M | `__uxtab16` | | UXTAH | | 6, 7E-M | `(uint16_t)x + i` | | UXTB16 | | 6, 7E-M | `__uxtb16` | | UXTH | | 8,6, 6-M | `(uint16_t)x` | | VFMA | | VFPv4 | `fma`, `__fma` | | VSQRT | | VFP | `sqrt`, `__sqrt` | | WFE | | 8,6K, 6-M | `__wfe` | | WFI | | 8,6K, 6-M | `__wfi` | | YIELD | | 8,6K, 6-M | `__yield` | # Advanced SIMD (Neon) intrinsics ## Introduction The Advanced SIMD instructions provide packed Single Instruction Multiple Data (SIMD) and single-element scalar operations on a range of integer and floating-point types. Neon is an implementation of the Advanced SIMD instructions which is provided as an extension for some Cortex-A Series processors. Where this document refers to Neon instructions, such instructions refer to the Advanced SIMD instructions as described by the Arm Architecture Reference Manual [[ARMARMv8]](#ARMARMv8). The Advanced SIMD extension provides for arithmetic, logical and saturated arithmetic operations on 8-bit, 16-bit and 32-bit integers (and sometimes on 64-bit integers) and on 32-bit and 64-bit floating-point data, arranged in 64-bit and 128-bit vectors. The intrinsics in this section provide C and C++ programmers with a simple programming model allowing easy access to code-generation of the Advanced SIMD instructions for both AArch64 and AArch32 execution states. ### Concepts The Advanced SIMD instructions are designed to improve the performance of multimedia and signal processing algorithms by operating on 64-bit or 128-bit *vectors* of *elements* of the same *scalar* data type. For example, `uint16x4_t` is a 64-bit vector type consisting of four elements of the scalar `uint16_t` data type. Likewise, `uint16x8_t` is a 128-bit vector type consisting of eight `uint16_t` elements. In a vector programming model, operations are performed in parallel across the elements of the vector. For example, `vmul_u16(a, b)` is a vector intrinsic which takes two `uint16x4_t` vector arguments `a` and `b`, and returns the result of multiplying corresponding elements from each vector together. The Advanced SIMD extension also provides support for *vector-by-lane* and *vector-by-scalar* operations. In these operations, a scalar value is extracted from one element of a vector input, or provided directly, duplicated to create a new vector with the same number of elements as an input vector, and an operation is performed in parallel between this new vector and other input vectors. For example, `vmul_lane_u16(a, b, 1)`, is a vector-by-lane intrinsic which takes two `uint16x4_t` vector elements. From `b`, element `1` is extracted, a new vector is formed which consists of four copies of element `1` of `b`, and this new vector is multiplied by `a`. *Reduction*, *cross-lane*, and *pairwise* vector operations work on pairs of elements within a vector, or across the whole of a single vector performing the same operation between elements of that vector. For example, `vaddv_u16(a)` is a reduction intrinsic which takes a `uint16x4_t` vector, adds each of the four `uint16_t` elements together, and returns a `uint16_t` result containing the sum. ### Vector data types Vector data types are named as a lane type and a multiple. Lane type names are based on the types defined in ``. For example,. `int16x4_t` is a vector of four `int16_t` values. The base types are `int8_t`, `uint8_t`, `int16_t`, `uint16_t`, `int32_t`, `uint32_t`, `int64_t`, `uint64_t`, `float16_t`, `float32_t`, `poly8_t`, `poly16_t`, `poly64_t`, `poly128_t` and `bfloat16_t`. The multiples are such that the resulting vector types are 64-bit and 128-bit. In AArch64, `float64_t` is also a base type. Not all types can be used in all operations. Generally, the operations available on a type correspond to the operations available on the corresponding scalar type. ACLE does not define whether `int64x1_t` is the same type as `int64_t`, or whether `uint64x1_t` is the same type as `uint64_t`, or whether `poly64x1_t` is the same as `poly64_t` for example for C++ overloading purposes. float16 types are only available when the `__fp16` type is defined, i.e. when supported by the hardware. bfloat types are only available when the `__bf16` type is defined, i.e. when supported by the hardware. The bfloat types are all opaque types. That is to say they can only be used by intrinsics. ### Advanced SIMD Scalar data types AArch64 supports Advanced SIMD scalar operations that work on standard scalar data types viz. `int8_t`, `uint8_t`, `int16_t`, `uint16_t`, `int32_t`, `uint32_t`, `int64_t`, `uint64_t`, `float32_t`, `float64_t`. ### Vector array data types Array types are defined for multiples of 2, 3 or 4 of all the vector types, for use in load and store operations, in table-lookup operations, and as the result type of operations that return a pair of vectors. For a vector type `_t` the corresponding array type is `x_t`. Concretely, an array type is a structure containing a single array element called val. For example an array of two `int16x4_t` types is `int16x4x2_t`, and is represented as ``` c struct int16x4x2_t { int16x4_t val[2]; }; ``` Note that this array of two 64-bit vector types is distinct from the 128-bit vector type `int16x8_t`. ### Scalar data types For consistency, `` defines some additional scalar data types to match the vector types. `float32_t` is defined as an alias for `float`. If the `__fp16` type is defined, `float16_t` is defined as an alias for it. If the `__bf16` type is defined, `bfloat16_t` is defined as an alias for it. `poly8_t`, `poly16_t`, `poly64_t` and `poly128_t` are defined as unsigned integer types. It is unspecified whether these are the same type as `uint8_t`, `uint16_t`, `uint64_t` and `uint128_t` for overloading and mangling purposes. `float64_t` is defined as an alias for `double`. ### 16-bit floating-point arithmetic scalar intrinsics The architecture extensions introduced by Armv8.2-A [[ARMARMv82]](#ARMARMv82) provide a set of data processing instructions which operate on 16-bit floating-point quantities. These instructions are available in both AArch64 and AArch32 execution states, for both Advanced SIMD and scalar floating-point values. ACLE defines two sets of intrinsics which correspond to these data processing instructions; a set of scalar intrinsics, and a set of vector intrinsics. The intrinsics introduced in this section use the data types defined by ACLE. In particular, scalar intrinsics use the `float16_t` type defined by ACLE as an alias for the `__fp16` type, and vector intrinsics use the `float16x4_t` and `float16x8_t` vector types. Where the scalar 16-bit floating point intrinsics are available, an implementation is required to ensure that including `` has the effect of also including ``. To only enable support for the scalar 16-bit floating-point intrinsics, the header `` may be included directly. ### 16-bit brain floating-point arithmetic scalar intrinsics The architecture extensions introduced by Armv8.6-A [[Bfloat16]](#Bfloat16) provide a set of data processing instructions which operate on brain 16-bit floating-point quantities. These instructions are available in both AArch64 and AArch32 execution states, for both Advanced SIMD and scalar floating-point values. The brain 16-bit floating-point format (bfloat) differs from the older 16-bit floating-point format (float16) in that the former has an 8-bit exponent similar to a single-precision floating-point format but has a 7-bit fraction. ACLE defines two sets of intrinsics which correspond to these data processing instructions; a set of scalar intrinsics, and a set of vector intrinsics. The intrinsics introduced in this section use the data types defined by ACLE. In particular, scalar intrinsics use the `bfloat16_t` type defined by ACLE as an alias for the `__bf16` type, and vector intrinsics use the `bfloat16x4_t` and `bfloat16x8_t` vector types. Where the 16-bit brain floating point intrinsics are available, an implementation is required to ensure that including `` has the effect of also including ``. To only enable support for the 16-bit brain floating-point intrinsics, the header `` may be included directly. When `__ARM_BF16_FORMAT_ALTERNATIVE` is defined to `1` then these types are storage only and cannot be used with anything other than ACLE intrinsics. The underlying type for them is `uint16_t`. ### Operations on data types ACLE does not define implicit conversion between different data types. E.g. ``` c int32x4_t x; uint32x4_t y = x; // No representation change float32x4_t z = x; // Conversion of integer to floating type ``` Is not portable. Use the `vreinterpret` intrinsics to convert from one vector type to another without changing representation, and use the `vcvt` intrinsics to convert between integer and floating types; for example: ``` c int32x4_t x; uint32x4_t y = vreinterpretq_u32_s32(x); float32x4_t z = vcvt_f32_s32(x); ``` ACLE does not define static construction of vector types. E.g. ``` c int32x4_t x = { 1, 2, 3, 4 }; ``` Is not portable. Use the `vcreate` or `vdup` intrinsics to construct values from scalars. In C++, ACLE does not define whether Advanced SIMD data types are POD types or whether they can be inherited from. ### Compatibility with other vector programming models ACLE does not specify how the Advanced SIMD Intrinsics interoperate with alternative vector programming models. Consequently, programmers should take particular care when combining the Advanced SIMD Intrinsics programming model with such programming models. For example, the GCC vector extensions permit initialising a variable using array syntax, as so ``` c #include "arm_neon.h" ... uint32x2_t x = {0, 1}; // GCC extension. uint32_t y = vget_lane_s32 (x, 0); // ACLE Neon Intrinsic. ``` But the definition of the GCC vector extensions is such that the value stored in y will depend on both the target architecture (AArch32 or AArch64) and whether the program is running in big- or little-endian mode. It is recommended that Advanced SIMD Intrinsics be used consistently: ``` c #include "arm_neon.h" ... const int temp[2] = {0, 1}; uint32x2_t x = vld1_s32 (temp); uint32_t y = vget_lane_s32 (x, 0); ``` ## Availability of Advanced SIMD intrinsics and Extensions ### Availability of Advanced SIMD intrinsics Advanced SIMD support is available if the `__ARM_NEON` macro is predefined (see [Advanced SIMD architecture extension (Neon)](#advanced-simd-architecture-extension-neon)). In order to access the Advanced SIMD intrinsics, it is necessary to include the `` header. ``` c #if __ARM_NEON #include /* Advanced SIMD intrinsics are now available to use. */ #endif ``` Some intrinsics are only available when compiling for the AArch64 execution state. This can be determined using the `__ARM_64BIT_STATE` predefined macro (see [Instruction set architecture (A32/T32/A64)](#instruction-set-architecture-a32t32a64)). ### Availability of 16-bit floating-point vector interchange types When the 16-bit floating-point data type `__fp16` is available as an interchange type for scalar values, it is also available in the vector interchange types `float16x4_t` and `float16x8_t`. When the vector interchange types are available, conversion intrinsics between vector of `__fp16` and vector of `float` types are provided. This is indicated by the setting of bit 1 in `__ARM_NEON_FP` (see [Neon floating-point](#neon-floating-point)). ``` c #if __ARM_NEON_FP & 0x1 /* 16-bit floating point vector types are available. */ float16x8_t storage; #endif ``` ### Availability of fused multiply-accumulate intrinsics Whenever fused multiply-accumulate is available for scalar operations, it is also available as a vector operation in the Advanced SIMD extension. When a vector fused multiply-accumulate is available, intrinsics are defined to access it. This is indicated by `__ARM_FEATURE_FMA` (see [Fused multiply-accumulate (FMA)](#fused-multiply-accumulate-fma)). ``` c #if __ARM_FEATURE_FMA /* Fused multiply-accumulate intrinsics are available. */ float32x4_t a, b, c; vfma_f32 (a, b, c); #endif ``` ### Availability of Armv8.1-A Advanced SIMD intrinsics The Armv8.1-A [[ARMARMv81]](#ARMARMv81) architecture introduces two new instructions: SQRDMLAH and SQRDMLSH. ACLE specifies vector and vector-by-lane intrinsics to access these instructions where they are available in hardware. This is indicated by `__ARM_FEATURE_QRDMX` (see [Rounding doubling multiplies](#rounding-doubling-multiplies)). : ``` c #if __ARM_FEATURE_QRDMX /* Armv8.1-A RDMA extensions are available. */ int16x4_t a, b, c; vqrdmlah_s16 (a, b, c); #endif ``` ### Availability of 16-bit floating-point arithmetic intrinsics Armv8.2-A [[ARMARMv82]](#ARMARMv82) introduces new data processing instructions which operate on 16-bit floating point data in the IEEE754-2008 [IEEE-FP] format. ACLE specifies intrinsics which map to the vector forms of these instructions where they are available in hardware. This is indicated by `__ARM_FEATURE_FP16_VECTOR_ARITHMETIC` (see [16-bit floating-point data processing operations](#16-bit-floating-point-data-processing-operations)). : ``` c #if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC float16x8_t a, b; vaddq_f16 (a, b); #endif ``` ACLE also specifies intrinsics which map to the scalar forms of these instructions, see [16-bit floating-point arithmetic scalar intrinsics](#16-bit-floating-point-arithmetic-scalar-intrinsics). Availability of the scalar intrinsics is indicated by `__ARM_FEATURE_FP16_SCALAR_ARITHMETIC`. ``` c #if __ARM_FEATURE_FP16_SCALAR_ARITHMETIC float16_t a, b; vaddh_f16 (a, b); #endif ``` ### Availability of 16-bit brain floating-point arithmetic intrinsics Armv8.2-A [[ARMARMv82]](#ARMARMv82) introduces new data processing instructions which operate on 16-bit brain floating point data as described in the Arm Architecture Reference Manual. ACLE specifies intrinsics which map to the vector forms of these instructions where they are available in hardware. This is indicated by `__ARM_FEATURE_BF16_VECTOR_ARITHMETIC` (see [Brain 16-bit floating-point support](#brain-16-bit-floating-point-support)). ``` c #if __ARM_FEATURE_BF16_VECTOR_ARITHMETIC float32x2_t res = {0}; bfloat16x4_t a' = vld1_bf16 (a); bfloat16x4_t b' = vld1_bf16 (b); res = vdot_bf16 (res, a', b'); #endif ``` ACLE also specifies intrinsics which map to the scalar forms of these instructions, see [16-bit brain floating-point arithmetic scalar intrinsics](#16-bit-brain-floating-point-arithmetic-scalar-intrinsics). Availability of the scalar intrinsics is indicated by `__ARM_FEATURE_BF16_SCALAR_ARITHMETIC`. ``` c #if __ARM_FEATURE_BF16_SCALAR_ARITHMETIC bfloat16_t a; float32_t b = ..; a = b (b); #endif ``` ### Availability of Armv8.4-A Advanced SIMD intrinsics New Crypto and FP16 Floating Point Multiplication Variant instructions in Armv8.4-A: * New SHA512 crypto instructions (available if `__ARM_FEATURE_SHA512`) * New SHA3 crypto instructions (available if `__ARM_FEATURE_SHA3`) * SM3 crypto instructions (available if `__ARM_FEATURE_SM3`) * SM4 crypto instructions (available if `__ARM_FEATURE_SM4`) * New FML[A\|S] instructions (available if `__ARM_FEATURE_FP16_FML`). These instructions have been backported as optional instructions to Armv8.2-A and Armv8.3-A. ### Availability of Dot Product intrinsics The architecture extensions introduced by Armv8.2-A provide a set of dot product instructions which operate on 8-bit sub-element quantities. These instructions are available in both AArch64 and AArch32 execution states using Advanced SIMD instructions. These intrinsics are available when `__ARM_FEATURE_DOTPROD` is defined (see [Dot Product extension](#dot-product-extension)). : ``` c #if __ARM_FEATURE_DOTPROD uint8x8_t a, b; vdot_u8 (a, b); #endif ``` ### Availability of Armv8.5-A floating-point rounding intrinsics The architecture extensions introduced by Armv8.5-A provide a set of floating-point rounding instructions that round a floating-point number to an to a floating-point value that would be representable in a 32-bit or 64-bit signed integer type. NaNs, Infinities and Out-of-Range values are forced to the Most Negative Integer representable in the target size, and an Invalid Operation Floating-Point Exception is generated. These instructions are available only in the AArch64 execution state. The intrinsics for these are available when `__ARM_FEATURE_FRINT` is defined. The Advanced SIMD intrinsics are specified in the Arm Neon Intrinsics Reference Architecture Specification [[Neon]](#Neon). ### Availability of Armv8.6-A Integer Matrix Multiply intrinsics The architecture extensions introduced by Armv8.6-A provide a set of integer matrix multiplication and mixed sign dot product instructions. These instructions are optional from Armv8.2-A to Armv8.5-A. These intrinsics are available when `__ARM_FEATURE_MATMUL_INT8` is defined (see [Matrix Multiply Intrinsics](#matrix-multiply-intrinsics)). ## Specification of Advanced SIMD intrinsics The Advanced SIMD intrinsics are specified in the Arm Neon Intrinsics Reference Architecture Specification [[Neon]](#Neon). The behavior of an intrinsic is specified to be equivalent to the AArch64 instruction it is mapped to in [[Neon]](#Neon). Intrinsics are specified as a mapping between their name, arguments and return values and the AArch64 instruction and assembler operands which they are equivalent to. A compiler may make use of the as-if rule from C [[C99]](#C99) (5.1.2.3) to perform optimizations which preserve the instruction semantics. ## Undefined behavior Care should be taken by compiler implementers not to introduce the concept of undefined behavior to the semantics of an intrinsic. For example, the `vabsd_s64` intrinsic has well defined behaviour for all input values, while the C99 `llabs` has undefined behaviour if the result would not be representable in a `long long` type. It would thus be incorrect to implement `vabsd_s64` as a wrapper function or macro around `llabs`. ## Alignment assertions The AArch32 Neon load and store instructions provide for alignment assertions, which may speed up access to aligned data (and will fault access to unaligned data). The Advanced SIMD intrinsics do not directly provide a means for asserting alignment. # SVE language extensions and intrinsics ## SVE introduction The Scalable Vector Extension (SVE) was introduced as an optional extension to the Arm8.2-A architecture. Its associated feature flag is FEAT_SVE. SVE has since been extended further by features such as Armv8.6-A's matrix multiplication extensions and Armv9-A's SVE2. For brevity, this document generally uses “SVE” to refer to the original FEAT_SVE version of SVE and all subsequent extensions to it. For example, references to “SVE” include “SVE2” except whether otherwise noted. ACLE defines a set of C and C++ types and accessors for SVE vectors and predicates. It also defines intrinsics for almost all SVE instructions. [Mapping of SVE instructions to intrinsics](#mapping-of-sve-instructions-to-intrinsics) lists each SVE instruction and links to the corresponding ACLE intrinsic (if one exists). However, the intrinsic interface is more general than the underlying architecture, so not every intrinsic maps directly to an architectural instruction. The intention is to provide a regular interface and leave the ACLE implementation to pick the best mapping to SVE instructions. ## SVE types ### Overview of SVE types SVE is a “vector-length agnostic” architecture. Instead of mandating a particular vector length, it allows implementations to choose any multiple of 128 bits up to the architectural maximum of 2048 bits. It also allows higher exception levels to constrain the vector lengths of lower exception levels. The effective vector length is therefore not a compile-time constant and can in principle change during execution. Although the architectural increment is 128 bits, it is often more natural to think in terms of 64-bit quantities. The term “VG” (“vector granules”) refers to the current number of 64-bit elements in an SVE vector, so that the number of usable bits in a vector is VG×64. Predicates have one bit for each vector byte, so the number of usable bits in a predicate is VG×8. Therefore, code that makes direct use of SVE instructions requires access to vector types that have VG×64 bits and predicate types that have VG×8 bits, but without the value of VG being fixed. Ideally it should be possible to pass and return these types by value, like it is for other (fixed-length) vector extensions. However, standard C and C++ do not provide variable-length types that are both self-contained (rather than dependent on separate storage) and suitable for passing and returning by value. (For example, C's variable-length arrays are self-contained but are not valid return types. C++'s `std::string` can store variable-length data and is suitable for passing and returning by value, but it relies on separately-allocated storage.) This means that there is no existing mechanism that maps directly to the concept of an SVE vector or predicate. Any approach to defining the types would fall into one of three categories: 1. Limit the types in such a way that there is no concept of size. 2. Define the size of the types to be variable. 3. Define the size of the types to be constant, with the constant being large enough for all possible VG or with the types pointing to separate memory (as for classes like `std::string`). ACLE takes the first approach and classifies SVE vectors and predicates as belonging to a new category of type called “sizeless types”. The next section describes these types in more detail. ### Sizeless types For the reasons explained in the previous section, ACLE defines a new category of type called “sizeless types”. They are less restrictive than the standard “incomplete types” but more restrictive than ”complete types”. SVE vectors and predicates have sizeless type. #### Informal definition of sizeless types Informally, sizeless types can be used in the following situations: * as the type of an object with automatic storage duration; * as a function parameter or return type; * as a type name in a `_Generic` association; * as the type in a `(type) {value}` compound literal; * as the type in a C++ `type()` expression; * as the target of a pointer or reference type; and * as a template type argument. Sizeless types may not be used in the following situations: * as the type of a variable with static or thread-local storage duration (regardless of whether the variable is being defined or just declared); * as the type of an array element; * as the operand to a `new` expression; and * as the type of object being deleted by a `delete` expression. In all other respects, sizeless types have the same restrictions as the standard-defined “incomplete types”. This specifically includes (but is not limited to) the following: * The argument to `sizeof` and `_Alignof` cannot be a sizeless type, or an object of sizeless type. * It is not possible to perform arithmetic on pointers to sizeless types. (This affects the `+`, `-`, `++` and `--` operators.) * Members of unions, structures and classes cannot have sizeless type. * `_Atomic` variables cannot have sizeless type. * It is not possible to throw or catch objects of sizeless type. * Lambda expressions cannot capture sizeless types by value, although they can capture them by reference. (This is a corollary of not allowing member variables to have sizeless type.) * Standard library containers like `std::vector` cannot have a sizeless `value_type`. #### Formal definition of sizeless types [Sizeless types in C](#sizeless-types-in-c) gives a more formal definition of sizeless types for C, in the form of an edit to the standard. [Sizeless types in C++](#sizeless-types-in-cxx) gives the corresponding changes for C++. Implementations should correctly compile any code that follows these rules, but they do not need to report a diagnostic for invalid uses of sizeless types. Whether they report a diagnostic or not is a quality of implementation issue. (Note: future versions of ACLE might have stricter diagnostic requirements.) ##### Sizeless types in C This section specifies the behavior of sizeless types as an edit to the N1570 version of the C standard. **6.2.5 Types** > In 6.2.5/1, replace: > > > At various points within a translation unit an object type may > > be *incomplete* ... > > onwards with: > > > Object types are further partitioned into *sized* and *sizeless*; > > all basic and derived types defined in this standard are sized, > > but an implementation may provide additional sizeless types. > > and add two additional clauses: > > > * At various points within a translation unit an object type > > may be *indefinite* (lacking sufficient information to > > construct an object of that type) or *definite* (having > > sufficient information). An object type is said to be > > *complete* if it is both sized and definite; all other object > > types are said to be *incomplete*. Complete types have > > sufficient information to determine the size of an object of > > that type while incomplete types do not. > > > > * Arrays, structures, unions and enumerated types are always > > sized, so for them the term *incomplete* is equivalent to (and > > used interchangeably with) the term *indefinite*. > > Change 6.2.5/19 to: > > > The `void` type comprises an empty set of values; it is a > > sized indefinite object type that cannot be completed (made > > definite). > > Replace *incomplete* with *indefinite* and *complete* with *definite* in > 6.2.5/37, which describes how a type's state can change throughout a > translation unit. **6.3.2.1 Lvalues, arrays, and function designators** > Replace *incomplete* with *indefinite* in 6.3.2.1/1, so that sizeless > definite types are modifiable lvalues. > > Make the same replacement in 6.3.2.1/2, to prevent undefined > behavior when lvalues have sizeless definite type. **6.5.1.1 Generic selection** > Replace *complete object type* with *definite object type* in 6.5.1.1/2, > so that the type name in a generic association can be a sizeless > definite type. **6.5.2.2 Function calls** > Replace *complete object type* with *definite object type* in 6.5.2.2/1, > so that functions can return sizeless definite types. > > Make the same change in 6.5.2.2/4, so that arguments can also have > sizeless definite type. **6.5.2.5 Compound literals** > Replace *complete object type* with *definite object type* in 6.5.2.5/1, > so that compound literals can have sizeless definite type. **6.7 Declarations** > Insert the following new clause after 6.7/4: > > > * If an identifier for an object does not have automatic storage > > duration, its type must be sized rather than sizeless. > > Replace *complete* with *definite* in 6.7/7, which describes when the > type of an object becomes definite. **6.7.6.3 Function declarators (including prototypes)** > Replace *incomplete type* with *indefinite type* in 6.7.6.3/4, so that > parameters can also have sizeless definite type. > > Make the same change in 6.7.6.3/12, which allows even indefinite > types to be function parameters if no function definition is > present. **6.7.9 Initialization** > Replace *complete object type* with *definite object type* in 6.7.9/3, > to allow initialization of identifiers with sizeless definite type. **6.9.1 Function definitions** > Replace *complete object type* with *definite object type* in 6.9.1/3, > so that functions can return sizeless definite types. > > Make the same change in 6.9.1/7, so that adjusted parameter types > can be sizeless definite types. **J.2 Undefined behavior** > Update the entries that refer to the clauses above. ##### Sizeless types in C++ This section specifies the behavior of sizeless types as an edit to the N3797 version of the C++ standard. **3.1 Declarations and definitions [basic.def]** > Replace *incomplete type* with *indefinite type* in 3.1/5, so that > objects can have sizeless definite type in some situations. Add a > new clause immediately afterwards: > > > * A program is ill-formed if any declaration of an object gives > > it both a sizeless type and either static or thread-local > > storage duration. **3.9 Types [basic.types]** > Replace 3.9/5 with these clauses: > > > * A class that has been declared but not defined, an > > enumeration type in certain contexts, or an array of unknown > > size or of indefinite element type, is an *indefinite object type*. > > Indefinite object types and the void types are *indefinite types*. > > Objects shall not be defined to have an indefinite type. > > > > * Object and void types are further partitioned into *sized* > > and *sizeless*; all basic and derived types defined in this > > standard are sized, but an implementation may provide > > additional sizeless types. > > > > * An object or void type is said to be *complete* if it is both > > sized and definite; all other object and void types are said > > to be *incomplete*. The term *completely-defined object type* > > is synonymous with *complete object type*. > > > > * Arrays, class types and enumeration types are always sized, > > so for them the term *incomplete* is equivalent to (and used > > interchangeably with) the term *indefinite*. > > Replace *incomplete types* with *indefinite types* in 3.9/7, which is > simply a cross-reference note. **3.9.1 Fundamental Types [basic.fundamental]** > Replace the second sentence of 3.9.1/9 with: > > > The `void` type is a sized indefinite type that cannot be > > completed (made definite). **3.9.2. Compound Types [basic.compound]** > Add “(including indefinite types)” after “Pointers to incomplete > types” in 3.9.2/3, to emphasize that pointers to incomplete types > are more restricted than pointers to complete types, even if the > types are definite. **3.10 Lvalues and rvalues [basic.lval]** > Replace *complete types* with *definite types* and *incomplete types* > with *indefinite types* in 3.10/4, so that prvalues can be sizeless > definite types. > > Replace *incomplete* with *indefinite* and *complete* with *definite* > in 3.10/7, which describes the modifiability of a pointer and the > object to which it points. **4.1 Lvalue-to-rvalue conversion [conv.lval]** > Replace *incomplete type* with *indefinite type* in 4.1/1, so that > glvalues of sizeless definite type can be converted to prvalues. **5.2.2 Function call [expr.call]** > Replace *completely-defined object type* with *definite object type* > and *incomplete class type* with *indefinite class type*, > so that parameters can have sizeless definite type. > > Replace *incomplete* with *indefinite* and *complete* with *definite* > in 5.2.2/11, so that functions can return sizeless definite types. **5.2.3 Explicit type conversion (function notation) [expr.type.conv]** > Replace *complete object type* with *definite object type* in 5.2.3/2, > so that the `T()` notation extends to sizeless definite types. **5.3.1 Unary operators [expr.unary.op]** > Replace *incomplete type* with *indefinite type* in 5.3.1/1. This simply > updates a cross-reference to the 4.1 change above. **5.3.5 Delete [expr.delete]** > Insert the following after the first sentence of 5.3.5/2 (which > describes the implicit conversion of an object type to a pointer type): > > > The type of the operand must now be a pointer to a sized type, > > otherwise the program is ill-formed. **8.3.4 Arrays [dcl.array]** > In 8.3.4/1, add *a sizeless type* to the list of types that the > element type `T` cannot have. **9.4.2 Static data members [class.static.data]** > Replace *an incomplete type* with *a sized indefinite type* in 9.4.2/2, > so that static data members cannot be declared with sizeless type. > > Add a new final clause: > > > * A static data member shall not have sizeless type. **14.3.1 Template type parameters [temp.arg.type]** > Add “(including an indefinite type)” after “an incomplete type” in > the note describing template type arguments, to emphasize that the > arguments can be sizeless. **20.10.4.3 Type properties [meta.unary.prop]** > Replace *complete* with *definite* in 20.10.4.3/3, so that the > situations in which an implementation may implicitly instantiate > template arguments remain the same as before. **20.10.6 Relationships between types [meta.rel]** > Replace *complete* with *definite* in 20.10.6/2, so that these > metaprogramming facilities extend to sized definite types. **20.10.7.5 Pointer modifications [meta.trans.ptr]** > Likewise replace *complete* with *definite* in the initial table, so > that these metaprogramming facilities also extend to sized definite types. #### Interaction between sizeless types and other extensions It is not feasible to reconcile the definition of sizeless types with each individual current and future extension to C and C++. Therefore, the default position is that extensions to C and C++ should treat sizeless types as incomplete types unless otherwise specified. ### Scalar types defined by `` [``](#arm_sve.h) includes `` and so provides standard types such as `uint32_t`. When included from C code, the header also includes `` and so provides the `bool` type. In addition, the header file defines the following scalar data types: | **Scalar type** | **Definition** | | --------------- | ---------------------- | | `float16_t` | equivalent to `__fp16` | | `float32_t` | equivalent to `float` | | `float64_t` | equivalent to `double` | If the feature macro `__ARM_FEATURE_BF16_SCALAR_ARITHMETIC` is defined, [``](#arm_sve.h) also includes [``](#arm_bf16.h), which defines the scalar 16-bit brain floating-point type `__bf16`. Then, under the control of the same feature macro, `` defines an alias of `__bf16` called `bfloat16_t`. ### SVE vector types [``](#arm_sve.h) defines the following sizeless types for single vectors: | **Signed integer** | **Unsigned integer** | **Floating-point** | | | -------------------- | -------------------- | -------------------- | -------------------- | | `svint8_t` | `svuint8_t` | | | | `svint16_t` | `svuint16_t` | `svfloat16_t` | `svbfloat16_t` | | `svint32_t` | `svuint32_t` | `svfloat32_t` | | | `svint64_t` | `svuint64_t` | `svfloat64_t` | | Each type `svBASE_t` is an opaque length-agnostic vector of `BASE_t` elements. The types in each row have the same number of elements and have twice as many elements as the types in the row below them. `svbfloat16_t` is only available if the header file also provides a definition of `bfloat16_t` (see [Scalar types defined by ``](#scalar-types-defined-by-arm_sve.h)). The other types are available unconditionally. [``](#arm_sve.h) also defines tuples of two, three, and four vectors, as follows: | **Signed integer** | **Unsigned integer** | **Floating-point** | | | -------------------- | -------------------- | --------------------- | -------------------- | | `svint8x2_t` | `svuint8x2_t` | | | | `svint16x2_t` | `svuint16x2_t` | `svfloat16x2_t` | `svbfloat16x2_t` | | `svint32x2_t` | `svuint32x2_t` | `svfloat32x2_t` | | | `svint64x2_t` | `svuint64x2_t` | `svfloat64x2_t` | | | | | | | | `svint8x3_t` | `svuint8x3_t` | | | | `svint16x3_t` | `svuint16x3_t` | `svfloat16x3_t` | `svbfloat16x3_t` | | `svint32x3_t` | `svuint32x3_t` | `svfloat32x3_t` | | | `svint64x3_t` | `svuint64x3_t` | `svfloat64x3_t` | | | | | | | | `svint8x4_t` | `svuint8x4_t` | | | | `svint16x4_t` | `svuint16x4_t` | `svfloat16x4_t` | `svbfloat16x4_t` | | `svint32x4_t` | `svuint32x4_t` | `svfloat32x4_t` | | | `svint64x4_t` | `svuint64x4_t` | `svfloat64x4_t` | | Each `svBASExN_t` is an opaque sizeless type that conceptually contains a sequence of N `svBASE_t`s, indexed starting at 0. It is available whenever the corresponding single-vector type is. ACLE provides the following intrinsics for creating and accessing these tuple types: [`svcreate2(svBASE_t x0, svBASE_t x1)`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcreate2) [`svcreate3(svBASE_t x0, svBASE_t x1, svBASE_t x2)`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcreate3) [`svcreate4(svBASE_t x0, svBASE_t x1, svBASE_t x2, svBASE_t x3)`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcreate4) > `svcreateN` returns a `svBASExN_t` in which the vector at index M has the > value given by `xM`. [`svset2(svBASEx2_t tuple, uint64_t imm_index, svBASE_t x)`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svset2) [`svset3(svBASEx3_t tuple, uint64_t imm_index, svBASE_t x)`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svset3) [`svset4(svBASEx4_t tuple, uint64_t imm_index, svBASE_t x)`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svset4) > `svsetN` returns a copy of `tuple` in which the vector at index > `imm_index` has the value given by `x`. `imm_index` must be an > integer constant expression in the range [0, N-1]. [`svget2(svBASEx2_t tuple, uint64_t imm_index)`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svget2) [`svget3(svBASEx3_t tuple, uint64_t imm_index)`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svget3) [`svget4(svBASEx4_t tuple, uint64_t imm_index)`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svget4) > `svgetN` returns the value of vector `imm_index` in `tuple`. `imm_index` > must be an integer constant expression in the range [0, N-1]. It is also possible to create completely-undefined vectors and tuples of vectors using [`svundef`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svundef_), [`svundef2`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svundef2), [`svundef3`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svundef3) and [`svundef4`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svundef4). ACLE provides two sets of intrinsics for converting between vector types and between vector tuple types: * The [`svreinterpret`](#sve-reinterpret-intrinsics) intrinsics simply reinterpret a vector (or vector tuple) of one type as a vector (or vector tuple) of another type, without changing any of the bits. * The [`svcvt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcvt_) intrinsics instead perform numerical conversion from one type to another, such as converting integers to floating-point values. To avoid any ambiguity between the two operations, ACLE does not allow C-style casting from one vector type to another. ### SVE predicate types [``](#arm_sve.h) defines a single sizeless predicate type `svbool_t`, which has enough bits to control an operation on a vector of bytes. The main use of predicates is to select elements in a vector. When the elements in the vector have *N* bytes, only the low bit in each sequence of *N* predicate bits is significant. For example, with bits of a predicate numbered from the least significant bit upwards, the elements selected by each bit are as follows: | | **bit 0** | **bit 1** | **bit 2** | **bit 3** | **bit 4** | **bit 5** | **bit 6** | **bit 7** | **bit 8** | | -------------------------: | :-------: | :-------: | :-------: | :-------: | :-------: | :-------: | :-------: | :-------: | :-------: | | **svuint8_t** element | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | | **svuint16_t** element | 0 | - | 1 | - | 2 | - | 3 | - | 4 | | **svuint32_t** element | 0 | - | - | - | 1 | - | - | - | 2 | | **svuint64_t** element | 0 | - | - | - | - | - | - | - | 1 | ### Fixed-length SVE types #### Introduction to fixed-length SVE types As described in [Overview of SVE types](#overview-of-sve-types), SVE is a “length-agnostic” architecture that supports a range of different vector register sizes. Some SVE ACLE code might be written to work with all of these register sizes; such code is fully “length-agnostic”. Other SVE ACLE code might instead require the register size to belong to a restricted set. Possible restrictions include imposing a minimum register size, a maximum register size, a power-of-two register size, or a single exact register size. This is a choice for the programmer to make. For example, the program snippet: ``` c svfloat32_t data = svld1(svptrue_pat_b32(SV_VL16), ptr); ``` loads no data when the vector registers are smaller than 512 bits, so in practice the code is likely to require a register size of 512 bits or more. Similarly, for any given piece of source code (whether it uses ACLE or not), a code generator might produce SVE object code that only correctly implements the source code for certain runtime register sizes. The code is likely to abort or malfunction if the registers have a different size. For example, if the code generator assumes that the vector register size is exactly 256 bits, it might use: ``` asm ADD X1, X2, #32 ``` instead of: ``` asm ADDVL X1, X2, #1 ``` Let SourceVL be the set of vector register sizes supported by a piece of SVE ACLE source code and ObjectVL be the set of vector register sizes for which the object code correctly implements the source code. In both cases, the set might be the set of all possible register sizes (referred to as “unrestricted” below). In general, object code created from SVE ACLE source code only works correctly when the runtime register size belongs to the intersection of SourceVL and ObjectVL. The behavior in other cases is undefined. The compiler might impose a fixed ObjectVL set for all code or provide a level of user control. It might also allow ObjectVL to vary within the program, either within the same translation unit or between different translation units. Whether and how this happens is currently outside the scope of ACLE. The combination of a singleton SourceVL and an unrestricted ObjectVL makes sense: ACLE source code written for a single register size can still be compiled correctly without knowing what that size is, just like an assembler can assemble SVE code without knowing what register sizes the assembly code supports. Similarly, the combination of a singleton ObjectVL and an unrestricted SourceVL makes sense: ACLE source code written for all register sizes can still be compiled for only a single register size, perhaps to try to improve the performance of surrounding code. Other combinations are also possible. This section describes ACLE features related to singleton ObjectVLs. They are intended to help cases in which SourceVL is the same singleton. All the features are optional: a conforming ACLE implementation does not need to provide them. Note: the types defined in [SVE vector types](#sve-vector-types) and [SVE predicate types](#sve-predicate-types) are always sizeless types and are subject to the same restrictions for all SourceVL and for all ObjectVL. #### The `__ARM_FEATURE_SVE_BITS` macro As an optional extension, an ACLE implementation may set the preprocessor macro: ``` c __ARM_FEATURE_SVE_BITS ``` to a nonzero value N provided that: * ObjectVL (see [Introduction to fixed-length SVE types](#introduction-to-fixed-length-sve-types) is a singleton vector register size of N bits; and * it is possible to apply the `arm_sve_vector_bits(N)` attribute to SVE vector types and SVE predicate types, as described in [The `arm_sve_vector_bits` attribute](#the-arm_sve_vector_bits-attribute). If the implementation allows ObjectVL to be changed within a translation unit, it must ensure that the value of the macro remains accurate after each change. `__ARM_FEATURE_SVE_BITS` would then have different values at different points in a translation unit. Defining the macro to zero has the same meaning as not defining it all. #### The `arm_sve_vector_bits` attribute ##### Syntax and requirements An ACLE implementation can choose to provide the following GNU-style type attribute: ``` c __attribute__((arm_sve_vector_bits(...arguments...))) ``` ACLE only defines the effect of the attribute if all of the following are true: 1. the attribute is attached to a single SVE vector type (such as `svint32_t`) or to the SVE predicate type `svbool_t`; 2. the arguments consist of a single nonzero integer constant expression (referred to as N below); and 3. `N==__ARM_FEATURE_SVE_BITS`. In other cases the implementation must do one of the following: * Ignore the attribute; a warning would then be appropriate, but is not required. * Reject the program with a diagnostic. * Extend requirement (3) above to support other values of N besides `__ARM_FEATURE_SVE_BITS`. * Process the attribute in accordance with a later revision of ACLE. ##### General `arm_sve_vector_bits` behavior Let VLST be a valid type: ``` c VLAT __attribute__((arm_sve_vector_bits(N))) ``` for some SVE vector type or SVE predicate type VLAT. VLST is then a fixed-length version of VLAT that is specialized for an N-bit SVE target. It is a normal sized (rather than sizeless) type, so unlike VLAT, it can be used as the type of a global variable, class member, `constexpr`, and so on. For example: ``` c #if __ARM_FEATURE_SVE_BITS==512 typedef svint32_t vec __attribute__((arm_sve_vector_bits(512))); typedef svbool_t pred __attribute__((arm_sve_vector_bits(512))); #endif ``` creates a type called `vec` that acts a fixed-length version of `svint32_t` and a type called `pred` that acts as a fixed-length version of `svbool_t`. Both types are normal sized types; `vec` contains exactly 512 bits (64 bytes) and `pred` contains exactly 64 bits (8 bytes): ``` c #if __ARM_FEATURE_SVE_BITS==512 typedef svint32_t vec __attribute__((arm_sve_vector_bits(512))); typedef svbool_t pred __attribute__((arm_sve_vector_bits(512))); svint32_t g1; // Invalid, svint32_t is sizeless vec g2; // OK svbool_t g3; // Invalid, svbool_t is sizeless pred g4; // OK struct wrap1 { svint32_t x; }; // Invalid, svint32_t is sizeless struct wrap2 { vec x; }; // OK struct wrap3 { svbool_t x; }; // Invalid, svbool_t is sizeless struct wrap4 { pred x; }; // OK size_t size1 = sizeof(svint32_t); // Invalid, svint32_t is sizeless size_t size2 = sizeof(vec); // OK, equals 64 size_t size3 = sizeof(svbool_t); // Invalid, svbool_t is sizeless size_t size4 = sizeof(pred); // OK, equals 8 #endif ``` The following rules apply to both vector and predicate VLST types: * Whenever `__ARM_FEATURE_SVE_BITS==N`, VLST implicitly converts to VLAT and VLAT implicitly converts to VLST. In C++, these conversions have a rank just below derived-to-base conversion. This behavior makes it possible to use VLST with ACLE intrinsics that operate on VLAT. For example: ``` c #if __ARM_FEATURE_SVE_BITS==512 typedef svbool_t pred __attribute__((arm_sve_vector_bits(512))); pred f(pred x, pred y) { return svbrka_z(x, y); } #endif ``` * A conditional expression of the form `C ? E1 : E2` is ill-formed if: * E1 has type VLAT or cv-qualified VLAT and E2 has type VLST or cv-qualified VLST; or * E1 has type VLST or cv-qualified VLST and E2 has type VLAT or cv-qualified VLAT. However, the implementation does not need to diagnose these cases. This rule avoids any ambiguity about whether the result of the conditional expression is sized or sizeless. For example: ``` c #if __ARM_FEATURE_SVE_BITS==512 typedef svint32_t vec __attribute__((arm_sve_vector_bits(512))); auto f(bool cond, vec x, svint32_t y) { return cond ? x : y; } #endif ``` is ill-formed because it is not clear whether the type of the result should come from `x` or `y`. * VLST maps to the same AAPCS64 ABI type as VLAT. For example: ``` c svint32_t __attribute__((arm_sve_vector_bits(128))) ``` maps to the same AAPCS64 type as `svint32_t`, rather than to the same AAPCS64 type as the `arm_neon.h` type `int32x4_t`. * An object type “requires size N” if: * it is an SVE vector type or SVE predicate type that has the attribute `arm_sve_vector_bits(N)`; * it is an array type whose element type requires size N; or * it is a class or struct and: * at least one non-static member has a type that requires size N; or * a base type requires size N Note: this definition specifically excludes reference and pointer types. * A function type “requires size N” if the return type requires size N or if at least one parameter type requires size N. * A program is ill-formed if: * any function type requires two different sizes N1 and N2. * `__ARM_FEATURE_SVE_BITS!=N` when defining a function whose type requires size N. * `__ARM_FEATURE_SVE_BITS!=N` when calling a function whose type requires size N. (Note that this explicitly excludes parameters passed through “`...`”.) * an object whose type requires some size N is passed to an [unprototyped function](#unprototyped-function). However, the implementation does not need to diagnose these cases. These rules only have an effect if an implementation allows the register size to vary within a translation unit. The aim is to forbid function definitions and function calls that have no mapping to the AAPCS64 calling conventions. For example, if an implementation supports some form of pragma that changes `__ARM_FEATURE_SVE_BITS` within a translation unit: ``` c ...pragma that changes __ARM_FEATURE_SVE_BITS to 256... typedef svfloat32_t vec256 __attribute__((arm_sve_vector_bits(256))); ...pragma that changes __ARM_FEATURE_SVE_BITS to 512... typedef svbool_t bool512 __attribute__((arm_sve_vector_bits(512))); struct mix1 { bool512 a; vec256 b; }; // OK struct mix2 { bool512 a; vec256 *b; }; // OK union mix3 { bool512 a; vec256 b; }; // OK typedef bool512 (*callback)(vec256); // Invalid, requires sizes 256, 512 bool512 f1(vec256); // Invalid, requires sizes 256, 512 vec256 f2(); // OK, just a declaration vec256 f3() { ... } // Invalid, requires size 256 void f4(struct mix1 m) { ... } // Invalid, requires sizes 256, 512 void f5(struct mix2 m) { ... } // OK, just requires size 512 void f6(union mix3 m) { ... } // OK, no size requirements bool512 f7() { ... } // OK, just requires size 512 void f8(bool512 *x, vec256 *y) { ... } // OK, no size requirements ``` See [`arm_sve_vector_bits` behavior specific to vectors](#arm_sve_vector_bits-behavior-specific-to-vectors) for additional rules that apply specifically to vectors and [`arm_sve_vector_bits` behavior specific to predicates](#arm_sve_vector_bits-behavior-specific-to-predicates) for additional rules that apply specifically to predicates. ##### `arm_sve_vector_bits` behavior specific to vectors If VLAT is an SVE vector type `svBASE_t` and VLST is a valid type: ``` c VLAT __attribute__((arm_sve_vector_bits(N))) ``` then VLST is a sized type that has the following properties: ``` c sizeof(VLST) == N/8 alignof(VLST) == 16 ``` If in addition the implementation defines the preprocessor macro ``` c __ARM_FEATURE_SVE_VECTOR_OPERATORS ``` and if VLAT is not `svbfloat16_t`, then: * The GNU `__attribute__((vector_size))` extension is available. * VLST supports the same forms of elementwise initialization as: ``` c BASE_t __attribute__((vector_size(N/8))) ``` (referred to as GNUT below). For example: ``` c #if __ARM_FEATURE_SVE_BITS==256 && __ARM_FEATURE_SVE_VECTOR_OPERATORS svint64_t vec __attribute__((arm_sve_vector_bits(256))) = { 0, 1, 2, 3 }; #endif ``` * VLST supports the same built-in C and C++ operators as GNUT. Any result that has type GNUT for GNUT operators has type VLST for VLST operators. For example: ``` c #if __ARM_FEATURE_SVE_BITS==512 && __ARM_FEATURE_SVE_VECTOR_OPERATORS typedef svint32_t vec __attribute__((arm_sve_vector_bits(512))); auto f(vec x, vec y) { return x + y; } // Returns a vec. #endif ``` * Whenever `__ARM_FEATURE_SVE_BITS==N`, GNUT implicitly converts to VLAT and VLAT implicitly converts to GNUT. In C++, these conversions have a rank just below derived-to-base conversion. This behavior makes it possible to use GNUT with ACLE intrinsics that operate on VLAT. For example: ``` c typedef int8_t vec __attribute__((vector_size(32))); #if __ARM_FEATURE_SVE_BITS==256 && __ARM_FEATURE_SVE_VECTOR_OPERATORS vec f(vec x) { return svasrd_x(svptrue_b8(), x, 1); } #endif ``` * Irrespective of `__ARM_FEATURE_SVE_BITS`, GNUT implicitly converts to VLST and VLST implicitly converts to GNUT. In C++, these conversions again have a rank just below derived-to-base conversion. This behavior makes it possible to use VLST with existing interfaces that operate on GNUT. For example: ``` c typedef int8_t vec1 __attribute__((vector_size(32))); void f(vec1); #if __ARM_FEATURE_SVE_BITS==256 && __ARM_FEATURE_SVE_VECTOR_OPERATORS typedef svint8_t vec2 __attribute__((arm_sve_vector_bits(256))); void g(vec2 x) { f(x); } // OK #endif ``` Also, if an implementation supports some form of pragma that changes `__ARM_FEATURE_SVE_BITS` within a translation unit: ``` c #ifdef __ARM_FEATURE_SVE_VECTOR_OPERATORS ...pragma that changes __ARM_FEATURE_SVE_BITS to 256... int8_t x __attribute__((vector_size(32))); svint8_t y __attribute__((arm_sve_vector_bits(256))); ...pragma that changes __ARM_FEATURE_SVE_BITS to 512... void f() { x = y; } // OK #endif ``` * A conditional expression of the form `C ? E1 : E2` is ill-formed if: * E1 has type VLAT or cv-qualified VLAT and E2 has type GNUT or cv-qualified GNUT; or * E1 has type GNUT or cv-qualified GNUT and E2 has type VLAT or cv-qualified VLAT. However, the implementation does not need to diagnose these cases. This rule avoids any ambiguity about whether the result of the conditional expression is sized or sizeless. For example: ``` c #if __ARM_FEATURE_SVE_BITS==512 && __ARM_FEATURE_SVE_VECTOR_OPERATORS typedef int32_t vec __attribute__((vector_size(64))); auto f(bool cond, vec x, svint32_t y) { return cond ? x : y; } #endif ``` is ill-formed because it is not clear whether the type of the result should come from `x` or `y`. The choice would affect the ABI of the function. * A binary expression of the form `E1 op E2` or a conditional expression of the form `C ? E1 : E2` is ill-formed if: * E1 has type VLST or cv-qualified VLST and E2 has type GNUT or cv-qualified GNUT; or * E1 has type GNUT or cv-qualified GNUT and E2 has type VLST or cv-qualified VLST. However, the implementation does not need to diagnose these cases. This rule avoids any ambiguity about whether the result of the expression is a GNU or SVE type. For example: ``` c #if __ARM_FEATURE_SVE_BITS==512 && __ARM_FEATURE_SVE_VECTOR_OPERATORS typedef int32_t vec1 __attribute__((vector_size(64))); typedef svint32_t vec2 __attribute__((arm_sve_vector_bits(512))); auto f(vec1 x, vec2 y) { return x + y; } #endif ``` is ill-formed because it is not clear whether the type of the result should come from `x` or `y`. The choice would affect the ABI of the function. ##### `arm_sve_vector_bits` behavior specific to predicates Let VLST be a valid type: ``` c svbool_t __attribute__((arm_sve_vector_bits(N))) ``` VLST is then a sized type that has the following properties: ``` c sizeof(VLST) == N/64 alignof(VLST) == 2 ``` If in addition the implementation defines the preprocessor macro ``` c __ARM_FEATURE_SVE_PREDICATE_OPERATORS ``` then: * The GNU `__attribute__((vector_size))` extension is available. * VLST supports the same forms of elementwise initialization as the vector type: ``` c uint8_t __attribute__((vector_size(N/8))) ``` except that the elements have type `bool` instead of `uint8_t`. * VLST supports the following operators, all of which take arguments of type VLST and return either a VLST or a reference to a VLST: * unary `~` * binary `&`, `|` and `^` * assignments `&=`, `|=` and `^=` * comparisons `<`, `<=`, `==`, `!=`, `>=` and `>` All operators behave analogously to GNU vectors. For example: ``` c #if __ARM_FEATURE_SVE_BITS==256 && __ARM_FEATURE_SVE_PREDICATE_OPERATORS typedef svbool_t pred __attribute__((arm_sve_vector_bits(256))); auto f(pred x, pred y) { return x & y; } // Returns a pred #endif ``` * VLST supports the array subscript operator `[]` in a way that behaves analogously to GNU vectors, except that it is not possible to take the address of the result. For example: ``` c #if __ARM_FEATURE_SVE_BITS==256 && __ARM_FEATURE_SVE_PREDICATE_OPERATORS typedef svbool_t pred __attribute__((arm_sve_vector_bits(256))); pred x; bool f() { x[1] = true; return x[0]; } #endif ``` * Within a byte, subscripts count from the least significant bit. For example: ``` c #if __ARM_FEATURE_SVE_BITS==256 && __ARM_FEATURE_SVE_PREDICATE_OPERATORS svbool_t p __attribute__((arm_sve_vector_bits(256))) = { 0, 1 }; #endif ``` sets the first byte of `p` to 2 for both big- and little-endian targets. An implementation can choose to provide other operators too, but it does not need to do so. Note that, at the time of writing, the GNU `vector_size` extension is not defined for `bool` elements, nor for packed vectors of single bits. The definition above is intended to be a conservative subset of what such an extension might provide. ##### C++ mangling of fixed-length SVE types Let VLST be a valid C++ type: ``` c VLAT __attribute__((arm_sve_vector_bits(N))) ``` for some SVE vector type or SVE predicate type VLAT. VLST is mangled in the same way as a template: ``` c template struct __SVE_VLS; ``` with the arguments: ``` c __SVE_VLS ``` For example: ``` c #if __ARM_FEATURE_SVE_BITS==512 // Mangled as 9__SVE_VLSIu11__SVInt32_tLj512EE typedef svint32_t vec __attribute__((arm_sve_vector_bits(512))); // Mangled as 9__SVE_VLSIu10__SVBool_tLj512EE typedef svbool_t pred __attribute__((arm_sve_vector_bits(512))); #endif ``` ## SVE enum declarations The following enum enumerates all the possible patterns returned by a PTRUE: ``` c enum svpattern { SV_POW2 = 0, SV_VL1 = 1, SV_VL2 = 2, SV_VL3 = 3, SV_VL4 = 4, SV_VL5 = 5, SV_VL6 = 6, SV_VL7 = 7, SV_VL8 = 8, SV_VL16 = 9, SV_VL32 = 10, SV_VL64 = 11, SV_VL128 = 12, SV_VL256 = 13, SV_MUL4 = 29, SV_MUL3 = 30, SV_ALL = 31 }; ``` The following enum lists the possible prefetch types: ``` c enum svprfop { SV_PLDL1KEEP = 0, SV_PLDL1STRM = 1, SV_PLDL2KEEP = 2, SV_PLDL2STRM = 3, SV_PLDL3KEEP = 4, SV_PLDL3STRM = 5, SV_PSTL1KEEP = 8, SV_PSTL1STRM = 9, SV_PSTL2KEEP = 10, SV_PSTL2STRM = 11, SV_PSTL3KEEP = 12, SV_PSTL3STRM = 13 }; ``` Both enums are defined by [``](#arm_sve.h). ## SVE intrinsics ### SVE naming convention The SVE ACLE intrinsics have the form: ``` c svbase[_disambiguator][_type0][_type1]...[_predication] ``` where the individual parts are as follows: **base** > For most intrinsics this is the lower-case name of an SVE > instruction, but with some adjustments: > > * The most common change is to drop `F`, `S` and `U` if they > stand for “floating-point”, “signed” and “unsigned” respectively, > in cases where this would duplicate information in the type > suffixes below. > > * Simple non-extending loads and non-truncating stores drop the > size suffix (`B`, `H`, `W` or `D`), which would always duplicate > information in the suffixes. > > * Conversely, extending loads always specify an explicit extension > type, since this information is not available in the suffixes. > A sign-extending load has the same base as the architectural > instruction (e.g. `ld1sb`) while a zero-extending load replaces > the `s` with a `u` (e.g. `ld1ub` for a zero-extending `LD1B`). > Thus [`svld1ub_u32`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1ub_u32) > zero-extends 8-bit data to a vector of > `uint32_t`s while [`svld1sb_u32`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1sb_u32) > sign-extends 8-bit data to a vector of `uint32_t`s. **disambiguator** > This field distinguishes between different forms of an intrinsic. > There are several common uses: > > * Load, store, prefetch, and ADR intrinsics use this field to > distinguish between different addressing modes. See > [SVE addressing modes](#sve-addressing-modes) for a detailed > description of these modes. > > * Arithmetic operations use the disambiguator `_n` when the final > operand is a scalar rather than a vector. See [SVE operations involving > vectors and scalars](#sve-operations-involving-vectors-and-scalars) > for more information about these operations. > > * Some predicate-based operations use the disambiguator `_pat` to > show that they operate on an explicit constant predicate pattern > like `MUL3` instead of either an all-true predicate or an `svbool_t`. **type0** **type1** ... > These fields list the types of vectors and predicates, starting with > the return type and continuing with the argument types. They do not > include the types of vector bases and displacements, which form part > of the addressing mode disambiguator instead. They also do not > include argument types that are uniquely determined by the previous > argument types and return type. > > For vectors the field is a type category followed by an element size > in bits: > > | **Type category** | **8-bit** | **16-bit** | **32-bit** | **64-bit** | > | ---------------------------- | --------- | ---------- | ---------- | ---------- | > | signed integers | `s8` | `s16` | `s32` | `s64` | > | unsigned integers | `u8` | `u16` | `u32` | `u64` | > | floating-point numbers | | `f16` | `f32` | `f64` | > | brain floating-point numbers | | `bf16` | | | > > For predicates the suffix is `b` followed by the size of the > associated data elements in bits, or simply `b` if the operation > does not assume a particular element size. For example, the intrinsic > for > > ``` asm > PTRUE Pd.B > ``` > > is [`svptrue_b8`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svptrue_b8) > while the intrinsic for > > ``` asm > PTRUE Pd.H > ``` > > is [`svptrue_b16`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[16]&q=svptrue_b16) > The intrinsic for: > > ``` asm > PFALSE Pd.B > ``` > > is [`svpfalse_b`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svpfalse_b) > rather than `svpfalse_b8` since the result is suitable for all element sizes. **predication** > This suffix describes the inactive elements in the result of a > predicated operation. It can be one of the following: > > **`z`** > > > Zero predication: set all inactive elements of the result to zero. > > **`m`** > > > Merge predication: copy all inactive elements from the first > > vector argument. > > > > Unary operations have a separate vector argument that comes > > before the general predicate; for example: > > > > ``` asm > > CLZ Zd.H, Pg/M, Zs.H > > ``` > > > > corresponds to: > > > > ``` c > > Zd = svclz_u16_m(Zd, Pg, Zs); > > ``` > > > > The argument does not need to be syntactically related to the result; > > calls such as: > > > > ``` c > > Zd = svclz_u16_m(svadd_u16_z(...), Pg, Zs); > > ``` > > > > are also valid. > > > > Binary and ternary operations reuse the first argument to the > > operation as the merge input; for example: > > > > ``` asm > > ADD Zd.S, Pg/M, Zd.S, Zs2.S > > ``` > > > > corresponds to: > > > > ``` c > > Zd = svadd_u32_m(Pg, Zd, Zs2); > > ``` > > > > where the `Zd` argument supplies both the values of inactive > > elements and the first operand to the addition. Again, the merge > > input does not need to be syntactically related to the result. > > **`x`** > > > “Don't-care” predication: set the inactive elements to > > **unknown** values. > > > > Warning: these values could be arbitrary register contents left > > around from a previous operation, so accidentally using the inactive > > elements could lead to data leakage. > > > > This form of predication removes the need to choose between > > zeroing and merging in cases where the inactive elements are > > unimportant. The code generator can then pick whichever form of > > instruction seems to give the best code. This includes using > > unpredicated instructions, where available and suitable. > > Predicated loads, predicated comparisons and predicated string match > operations are always zeroing operations, so for brevity, the > corresponding intrinsics have no predication suffix. ### Overloaded aliases of SVE intrinsics The intrinsic names that are described in [SVE naming convention](#sve-naming-convention) often carry information that is obvious from the types of the arguments. For example, `svclz_u16_z` always takes a `svuint16_t` and no other form of `svclz_type_z` does. ACLE therefore defines shorter, overloaded, aliases that are compatible with both C++ overloading and C `_Generic` associations. At a minimum, this means that all overloaded forms of an intrinsic have the same number of arguments and that it is possible to select the correct overload by considering each argument from left to right. (Although the overloading scheme is compatible with `_Generic`, a C implementation can use other implementation-specific ways of achieving the same effect.) The usual integer promotions mean that overloading based on scalar integer types can be non-obvious. For example, in the C++ code: ``` c int f(unsigned char) { return 1; } int f(int) { return 2; } int g1(unsigned char c) { return f(c); } int g2(unsigned char c) { return f(c + 1); } ``` `g1` returns 1 but `g2` returns 2. A cast would be required to make `g2` use the `unsigned char` version of `f` instead of the `int` version. For this reason, ACLE does not use overloading of scalar arguments alone to determine the type of a vector result. Intrinsics like `svdup` and `svindex` (whose only arguments are scalar) always require a suffix indicating the return type. Overloaded aliases are always a full intrinsic name with parts of the suffix removed. The rest of this document refers to both the full intrinsic name and its overloaded alias by enclosing the elided suffix characters in square brackets. For example: ``` c svclz[_u16]_m ``` says that the full name is `svclz_u16_m` and that its overloaded alias is `svclz_m`. ### SVE addressing modes Load, store, prefetch, and ADR intrinsics have different forms for different addressing modes. The exact set of addressing modes depends on the particular operation, but they always have a base component and may also have a displacement component. The base may be either a single C pointer or a vector of address values. In the latter case, the address values may be 32 or 64 bits in size. Addressing modes with vector bases use the disambiguator `[_xNNbase]`, where `xNN` is the type of the address vector elements. The displacement, if present, may be a 64-bit scalar or a vector of 32-bit or 64-bit elements. There are five forms in total, with the following disambiguators: **`_offset`** > The displacement is a 64-bit scalar byte count. **`_index`** > The displacement is a 64-bit scalar element count. For example, if an > intrinsic loads 16-bit elements from memory, an `_index` displacement > of 1 is equivalent to an `_offset` displacement of 2. **`_vnum`** > The displacement is a 64-bit scalar that counts a single vector's > worth of elements. For example, if an intrinsic loads one or more full > vectors from memory, a `_vnum` displacement of 1 is equivalent to > an `_offset` displacement of VG×8 (the number of bytes in an SVE > vector). If an intrinsic loads 16-bit elements and extends them to > 32 bits, a `_vnum` displacement of 1 is equivalent to an `_offset` > displacement of VG×4 (half the number of bytes in an SVE vector). > > This form corresponds to the `MUL VL` addressing mode. However, > the displacement argument can be any scalar value; it does not need > to be a constant in a particular range. **`_[xNN]offset`** > The displacement is a vector of type `xNN` and each element specifies > a separate byte count. In other words: > > * `_[s32]offset` specifies a vector of signed 32-bit byte counts > and is equivalent to the `SXTW` addressing mode. > > * `_[u32]offset` specifies a vector of unsigned 32-bit byte counts > and is equivalent to the `UXTW` addressing mode. > > * `_[s64]offset` and `_[u64]offset` both specify vectors of 64-bit byte > counts; the sign is unimportant in this case. **`_[xNN]index`** > Similar to `_[xNN]offset`, but each element specifies an element > count rather than a byte count, in the same way as for `_index`. These displacements do not need to be constant and they do not need to be within a specific range. For example, the simplest load addressing mode is: ``` c svint16_t svld1[_s16](svbool_t pg, const int16_t *base) ``` which loads N elements from `base[0]` to `base[N-1]` inclusive. It is possible to apply a displacement measured in whole vectors using: ``` c svint16_t svld1_vnum[_s16](svbool_t pg, const int16_t *base, int64_t vnum) ``` which loads N elements from `base[N*vnum]` to `base[N*vnum+N-1]` inclusive. The following intrinsic instead takes a vector of offsets, measured in bytes: ``` c svuint32_t svld1_gather_[s32]offset[_u32](svbool_t pg, const uint32_t *base, svint32_t offsets) ``` In this case the address of element i is: ``` c (int32_t *)((uintptr_t)base + offsets[i]) ``` For: ``` c svuint32_t svld1_gather_[s32]index[_u32](svbool_t pg, const uint32_t *base, svint32_t indices) ``` the address of element i is simply `&base[indices[i]]`. The following intrinsic is an example of one that combines a vector base with a scalar index: ``` c svint32_t svld1_gather[_u32base]_index_s32(svbool_t pg, svuint32_t bases, int64_t index) ``` The address of element i is: ``` c ((int32_t *)(uintptr_t)bases[i]) + index ``` ### SVE operations involving vectors and scalars Some of the SVE instructions have immediate forms; for example: ``` c ADD Zd.S, Zd.S, #1 ``` adds 1 to every element of `Zd.S`. ACLE extends this approach to all arithmetic operations and to all scalar inputs (not just immediates). The implementation can then use immediate forms where possible or duplicate the scalar into a vector otherwise. For example: ``` c svint32_t x; ... x = svadd[_n_s32]_x(pg, x, 1); ``` adds 1 to every active element of `x` while: ``` c svfloat64_t x; double *ptr; ... x = svadd[_n_f64]_x(pg, x, *ptr); ``` adds `*ptr` to every active element of `x`. The first example is likely to use the immediate form of ADD while the latter is likely to use LD1RD. In a vector operation, the disambiguator `_n` indicates that the final operand is a scalar rather than a vector. ### Immediate arguments to SVE intrinsics Some intrinsics take enumeration values as arguments. These enumerations must always be integer constant expressions that specify a valid enumeration value. A few intrinsics take general integer immediates as arguments. In the [intrinsics documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiessimdisa=[sve,sve2]), these arguments always start with the prefix `imm`. Immediate arguments must be integer constant expressions within a certain range (which is the same as the range of the underlying SVE instruction). ### Faults and exceptions in SVE intrinsics Loads and stores can trigger faults in the same way as normal pointer dereferences. Exactly what happens then depends on the host environment and is out of scope for this document. However, these faults should be symptoms of a program going wrong rather than something that the programmer deliberately planted. The implementation can therefore remove or reorder potentially faulting operations as long as: * doing so would not cause a previously non-faulting program to fault; and * faults do not move between C++ exception blocks, in cases where faults are reported as exceptions. Also, many floating-point operations can raise IEEE exceptions. A similar set of rules apply there: the implementation can remove or reorder operations that might raise an IEEE exception if: * doing so would not cause a program to raise IEEE exceptions in cases where it would not previously; * IEEE exceptions do not move between C++ exception blocks, in cases where IEEE exceptions are reported as C++ exceptions; and * IEEE exceptions do not move across functions that manipulate the IEEE exception state. For example, the compiler can remove a floating-point addition whose result is not used. It can also reorder independent floating-point operations, even if that would change the order that exceptions occur. It cannot however move floating-point addition across a direct or indirect call to `feclearexcept` unless it can prove that the addition would not raise an exception. Many code generators have a mode that ignores IEEE exceptions. The floating-point restrictions above would not apply when such a mode is in effect. ### First-faulting and non-faulting loads SVE provides load instructions in which only the first active element can fault, and others in which no elements can fault. A special register called the first-fault register (FFR) records which elements were loaded successfully. The FFR describes all loads that have executed since the last write to the register. If a first-faulting or non-faulting load does not load an active element due to a potential fault, it clears the FFR from that element onwards. Those elements of the returned vector then have an unknown value. Elements also have an unknown value if the associated FFR element was *already* clear before the instruction started. For example, in: ``` asm SETFFR LDFF1D Z0.D, P0/Z, [X0] LDFF1D Z1.D, P1/Z, [X1] LDFF1D Z2.D, P2/Z, [X2] RDFFR P3.B ``` the load of `Z0.D` might suppress the load of `[X0, #16]` due to a potential fault. It would then clear bit 16 onwards of the FFR and leave elements 2 onwards of `Z0.D` in an unknown state. The same elements of `Z1.D` and `Z2.D` would then also be unknown, regardless of whether the loads based on `X1` or `X2` might fault. At the end of the sequence, `P3.B` indicates which elements of `Z0.D`, `Z1.D` and `Z2.D` are valid. In this sequence, the leading inactive elements of `Z0.D` are guaranteed to be zero and the first active element is guaranteed to be valid (assuming that the first element did not trigger a fault). The same guarantees apply to `Z1.D` only if the first active element of `P1` is guaranteed to be earlier than the second active element of `P0`. In this sense, the contents of `Z0.D`, `Z1.D` and `Z2.D` do depend on the order of the instructions, since the guarantees would be different if the loads had a different order. However, the point of the loads is to try to access more than the first active element, so these relationships are not useful in practice. ACLE therefore divides first-faulting and non-faulting loads (but not normal loads) into “FFR groups”. Each group begins and ends with an intrinsic that explicitly reads from or writes to the FFR. More precisely, ACLE introduces a global “first-fault register token” (FFRT) that identifies the current FFR group. This FFRT is a purely conceptual construct and contains three pieces of information: | **Identifier** | **Contents** | | -------------- | -------------------------------------------------------------- | | *nwrite* | the number of explicit writes to the FFR | | *lastwrite* | the last value written to the FFR | | *nread* | the number of explicit reads from the FFR since the last write | There are only two possible ways of modifying this FFRT: 1. Increment *nwrite* by one, set *lastwrite* to a given value, and set *nread* to zero. 2. Increment *nread* by one. Intrinsics that explicitly write to the FFR do the first operation. Intrinsics that explicitly read from the FFR do the second operation. First-faulting and non-faulting loads read from the FFRT and depend on its value, but they do not write to it. One consequence of this arrangement is that an intrinsic that writes to the FFR is only dead if there are no further references to the FFRT in the program. However, the normal “as if” rules apply, so the implementation can produce an empty code sequence for the write if doing so would not affect the behavior of the program. Similarly, if a first-faulting or non-faulting load follows an intrinsic that explicitly reads from the FFR, without an intervening write, the load keeps the read intrinsic alive even if the result of that read is unused. Again, the normal “as if” rules mean that the implementation can produce an empty code sequence for the read if doing so would not affect the behavior of the program. These FFRT dependencies are the only FFR-based ones that the implementation needs to consider when optimizing first-faulting and non-faulting loads; in all other respects the implementation can treat the loads like normal loads. This includes removing loads whose results are not used, suppressing loads of individual elements if their values do not matter, or reordering loads within a group (subject to the usual rules for normal loads). In practice the value of the FFR before a load does still affect which elements of the load result are defined, and in practice the loads do still write to the FFR, but the input program does not control these effects directly. Assuming `float64_t` data, the C version of the code above would be: ``` c svfloat64_t z0, z1, z2; svbool_t p0, p1, p2, p3; double *x0, *x1, *x2; ... svsetffr(); z0 = svldff1[_f64](p0, x0); z1 = svldff1[_f64](p1, x1); z2 = svldff1[_f64](p2, x2); p3 = svrdffr(); ``` ### SVE reinterpret intrinsics The `svreinterpret` intrinsics for vector types and vector tuple types take the form ``` c svreinterpret_type0[_type1_xN] ``` where `N` refers to the number of elements in a tuple type (2, 3, or 4). For example: ``` c svuin16_t svreinterpret_u16_s32(svint32_t op); svuin16_t svreinterpret_u16(svint32_t op); svuin16x2_t svreinterpret_u16_s32_x2(svint32x2_t op); svuin16x2_t svreinterpret_u16(svint32x2_t op); ``` A list of SVE reinterpret intrinsics can be found on [developer.arm.com](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svreinterpret). ### List of SVE intrinsics The list of SVE intrinsics can be found on [developer.arm.com](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiessimdisa=[sve,sve2]). This list includes SVE2 and other SVE extensions (such as the 32-bit matrix multiply extensions). The tick boxes on the left can be used to narrow the displayed intrinsics to particular data types and element sizes. Below that is an instruction group hierarchy that groups the intrinsics based on the operation that they perform. ### Mapping of SVE instructions to intrinsics #### List of instructions This section contains a list of all SVE instructions. For each one it gives a reference to the associated ACLE intrinsic or explains why no such intrinsic exists. The list includes SVE2 and other SVE extensions (such as the 32-bit matrix multiply extensions). | **Instruction** | **Intrinsic** | | ------------------------------------ | ------------- | | ABS | [`svabs`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svabs) | | ADCLB | [`svadclb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svadclb) | | ADCLT | [`svadclt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svadclt) | | ADD (immediate) | [`svadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svadd[) | | ADD (vectors, predicated) | [`svadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svadd[) | | ADD (vectors, unpredicated) | [`svadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svadd[) | | ADDHNB | [`svaddhnb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svaddhnb) | | ADDHNT | [`svaddhnt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svaddhnt) | | ADDP | [`svaddp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int,uint]&q=svaddp) | | ADDPL | See [ADDPL, ADDVL, INC and DEC](#addpl-addvl-inc-and-dec) | | ADDVL | See [ADDPL, ADDVL, INC and DEC](#addpl-addvl-inc-and-dec) | | ADR | [`svadrb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svadrb), [`svadrh`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svadrh), [`svadrw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svadrw), [`svadrd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svadrd) | | AESD | [`svaesd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svaesd) | | AESE | [`svaese`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svaese) | | AESIMC | [`svaesimc`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svaesimc) | | AESMC | [`svaesmc`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svaesmc) | | AND (immediate) | [`svand`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int,uint]&q=svand[) | | AND (predicates) | [`svand`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=svand) | | AND (vectors, predicated) | [`svand`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int,uint]&q=svand[) | | AND (vectors, unpredicated) | [`svand`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int,uint]&q=svand[) | | ANDS | [`svand`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=svand) | | ANDV | [`svandv`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svandv) | | ASR (immediate, predicated) | [`svasr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svasr[) | | ASR (immediate, unpredicated) | [`svasr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svasr[) | | ASR (vectors) | [`svasr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svasr[) | | ASR (wide elements, predicated) | [`svasr_wide`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svasr_wide) | | ASR (wide elements, unpredicated) | [`svasr_wide`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svasr_wide) | | ASRD | [`svasrd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svasrd) | | ASRR | [`svasr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svasr) (optimization of `_x` forms) | | BCAX | [`svbcax`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbcax) | | BDEP | [`svbdep`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbdep) | | BEXT | [`svbext`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbext) | | BFCVT | [`svcvt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcvt_bf16) | | BFCVTNT | [`svcvtnt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcvtnt_bf16) | | BFDOT | [`svbfdot`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbfdot) | | BFMLALB | [`svbfmlalb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbfmlalb) | | BFMLALT | [`svbfmlalt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbfmlalt) | | BFMMLA | [`svbfmmla`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbfmmla) | | BGRP | [`svbgrp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbgrp) | | BIC (immediate) | [`svbic`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int,uint]&q=svbic[) | | BIC (predicates) | [`svbic`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=svbic) | | BIC (vectors, predicated) | [`svbic`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int,uint]&q=svbic[) | | BIC (vectors, unpredicated) | [`svbic`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int,uint]&q=svbic[) | | BICS | [`svbic`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=svbic) | | BRKA | [`svbrka`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbrka) | | BRKAS | [`svbrka`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbrka) | | BRKB | [`svbrkb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbrkb) | | BRKBS | [`svbrkb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbrkb) | | BRKN | [`svbrkn`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbrkn) | | BRKNS | [`svbrkn`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbrkn) | | BRKPA | [`svbrkpa`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbrkpa) | | BRKPAS | [`svbrkpa`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbrkpa) | | BRKPB | [`svbrkpb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbrkpb) | | BRKPBS | [`svbrkpb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbrkpb) | | BSL | [`svbsl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbsl[) | | BSL1N | [`svbsl1n`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbsl1n) | | BSL2N | [`svbsl2n`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svbsl2n) | | CADD | [`svcadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcadd) | | CDOT (indexed) | [`svcdot_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcdot_lane) | | CDOT (vectors) | [`svcdot`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcdot[) | | CLASTA (SIMD & FP scalar) | [`svclasta`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svclasta) | | CLASTA (scalar) | [`svclasta`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svclasta) | | CLASTA (vectors) | [`svclasta`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svclasta) | | CLASTB (SIMD & FP scalar) | [`svclastb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svclastb) | | CLASTB (scalar) | [`svclastb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svclastb) | | CLASTB (vectors) | [`svclastb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svclastb) | | CLS | [`svcls`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcls) | | CLZ | [`svclz`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svclz) | | CMLA (indexed) | [`svcmla_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int,uint]&q=svcmla_lane) | | CMLA (vectors) | [`svcmla`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int,uint]&q=svcmla[) | | CMPEQ (immediate) | [`svcmpeq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svcmpeq[) | | CMPEQ (vectors) | [`svcmpeq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svcmpeq[) | | CMPEQ (wide elements) | [`svcmpeq_wide`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcmpeq_wide) | | CMPGE (immediate) | [`svcmpge`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svcmpge[) | | CMPGE (vectors) | [`svcmpge`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svcmpge[) | | CMPGE (wide elements) | [`svcmpge_wide`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svcmpge_wide) | | CMPGT (immediate) | [`svcmpgt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svcmpgt[) | | CMPGT (vectors) | [`svcmpgt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svcmpgt[) | | CMPGT (wide elements) | [`svcmpgt_wide`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svcmpgt_wide) | | CMPHI (immediate) | [`svcmpgt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svcmpgt[) | | CMPHI (vectors) | [`svcmpgt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svcmpgt[) | | CMPHI (wide elements) | [`svcmpgt_wide`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svcmpgt_wide) | | CMPHS (immediate) | [`svcmpge`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svcmpge[) | | CMPHS (vectors) | [`svcmpge`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svcmpge[) | | CMPHS (wide elements) | [`svcmpge_wide`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svcmpge_wide) | | CMPLE (immediate) | [`svcmple`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svcmple[) | | CMPLE (vectors) | [`svcmple`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svcmple[) | | CMPLE (wide elements) | [`svcmple_wide`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svcmple_wide) | | CMPLO (immediate) | [`svcmplt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svcmplt[) | | CMPLO (vectors) | [`svcmplt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svcmplt[) | | CMPLO (wide elements) | [`svcmplt_wide`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svcmplt_wide) | | CMPLS (immediate) | [`svcmple`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svcmple[) | | CMPLS (vectors) | [`svcmple`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svcmple[) | | CMPLS (wide elements) | [`svcmple_wide`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svcmple_wide) | | CMPLT (immediate) | [`svcmplt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svcmplt[) | | CMPLT (vectors) | [`svcmplt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svcmplt[) | | CMPLT (wide elements) | [`svcmplt_wide`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svcmplt_wide) | | CMPNE (immediate) | [`svcmpne`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svcmpne[) | | CMPNE (vectors) | [`svcmpne`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svcmpne[) | | CMPNE (wide elements) | [`svcmpne_wide`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svcmpne_wide) | | CNOT | [`svcnot`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcnot) | | CNT | [`svcnt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcnt[) | | CNTB | [`svcntb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcntb) | | CNTD | [`svcntd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcntd) | | CNTH | [`svcnth`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcnth) | | CNTP | [`svcntp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcntp) | | CNTW | [`svcntw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcntw) | | COMPACT | [`svcompact`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcompact) | | CPY (SIMD & FP scalar) | [`svdup`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdup[_n]) (predicated forms) | | CPY (immediate) | [`svdup`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdup[_n]) (predicated forms) | | CPY (scalar) | [`svdup`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdup[_n]) (predicated forms) | | CTERMEQ | See [CTERMEQ and CTERMNE](#ctermeq-and-ctermne) | | CTERMNE | See [CTERMEQ and CTERMNE](#ctermeq-and-ctermne) | | DECB | See [ADDPL, ADDVL, INC and DEC](#addpl-addvl-inc-and-dec) | | DECD (scalar) | See [ADDPL, ADDVL, INC and DEC](#addpl-addvl-inc-and-dec) | | DECD (vector) | See [ADDPL, ADDVL, INC and DEC](#addpl-addvl-inc-and-dec) | | DECH (scalar) | See [ADDPL, ADDVL, INC and DEC](#addpl-addvl-inc-and-dec) | | DECH (vector) | See [ADDPL, ADDVL, INC and DEC](#addpl-addvl-inc-and-dec) | | DECP (scalar) | See [ADDPL, ADDVL, INC and DEC](#addpl-addvl-inc-and-dec) | | DECP (vector) | See [ADDPL, ADDVL, INC and DEC](#addpl-addvl-inc-and-dec) | | DECW (scalar) | See [ADDPL, ADDVL, INC and DEC](#addpl-addvl-inc-and-dec) | | DECW (vector) | See [ADDPL, ADDVL, INC and DEC](#addpl-addvl-inc-and-dec) | | DUP (immediate) | [`svdup`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdup[_n]), [`svdupq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdupq[_n]) | | DUP (indexed) | [`svdup_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdup_lane), [`svdupq_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdupq_lane) | | DUP (scalar) | [`svdup`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdup[_n]), [`svdupq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdupq[_n]) | | DUPM | [`svdup`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdup[_n]), [`svdupq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdupq[_n]) | | EON | [`sveor`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int,uint]&q=sveor[) | | EOR (immediate) | [`sveor`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int,uint]&q=sveor[) | | EOR (predicates) | [`sveor`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=sveor) | | EOR (vectors, predicated) | [`sveor`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int,uint]&q=sveor[) | | EOR (vectors, unpredicated) | [`sveor`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int,uint]&q=sveor[) | | EOR3 | [`sveor3`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=sveor3) | | EORBT | [`sveorbt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=sveorbt) | | EORS | [`sveor`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=sveor) | | EORTB | [`sveortb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=sveortb) | | EORV | [`sveorv`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=sveorv) | | EXT | [`svext`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svext[) | | FABD | [`svabd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svabd[) | | FABS | [`svabs`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svabs) | | FACGE | [`svacge`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svacge) | | FACGT | [`svacgt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svacgt) | | FACLE | [`svacle`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svacle) | | FACLT | [`svaclt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svaclt) | | FADD (immediate) | [`svadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svadd[) | | FADD (vectors, predicated) | [`svadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svadd[) | | FADD (vectors, unpredicated) | [`svadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svadd[) | | FADDA | [`svadda`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svadda) | | FADDP | [`svaddp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svaddp) | | FADDV | [`svaddv`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svaddv) | | FCADD | [`svcadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svcadd) | | FCMEQ (vectors) | [`svcmpeq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svcmpeq) | | FCMEQ (zero) | [`svcmpeq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svcmpeq) | | FCMGE (vectors) | [`svcmpge`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svcmpge) | | FCMGE (zero) | [`svcmpge`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svcmpge) | | FCMGT (vectors) | [`svcmpgt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svcmpgt) | | FCMGT (zero) | [`svcmpgt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svcmpgt) | | FCMLA (indexed) | [`svcmla`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svcmla) | | FCMLA (vectors) | [`svcmla`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svcmla) | | FCMLE (vectors) | [`svcmple`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svcmple) | | FCMLE (zero) | [`svcmple`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svcmple) | | FCMLT (vectors) | [`svcmplt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svcmplt) | | FCMLT (zero) | [`svcmplt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svcmplt) | | FCMNE (vectors) | [`svcmpne`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svcmpne) | | FCMNE (zero) | [`svcmpne`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svcmpne) | | FCMUO | [`svcmpuo`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svcmpuo) | | FCPY | [`svdup`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svdup) (predicated forms) | | FCVT | [`svcvt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcvt_) | | FCVTLT | [`svcvtlt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcvtlt) | | FCVTNT | [`svcvtnt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcvtnt_f) | | FCVTX | [`svcvtx`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcvtx_) | | FCVTXNT | [`svcvtxnt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcvtxnt) | | FCVTZS | [`svcvt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcvt_) | | FCVTZU | [`svcvt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcvt_) | | FDIV | [`svdiv`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svdiv[) | | FDIVR | [`svdivr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svdivr) | | FDUP | [`svdup`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svdup[_n]) | | FEXPA | [`svexpa`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svexpa) | | FLOGB | [`svlogb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svlogb) | | FMAD | [`svmad`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmad) | | FMAX (immediate) | [`svmax`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmax[) | | FMAX (vectors) | [`svmax`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmax[) | | FMAXNM (immediate) | [`svmaxnm`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmaxnm[) | | FMAXNM (vectors) | [`svmaxnm`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmaxnm[) | | FMAXNMP | [`svmaxnmp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmaxnmp) | | FMAXNMV | [`svmaxnmv`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmaxnmv) | | FMAXP | [`svmaxp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmaxp) | | FMAXV | [`svmaxv`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmaxv) | | FMIN (immediate) | [`svmin`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmin[) | | FMIN (vectors) | [`svmin`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmin[) | | FMINNM (immediate) | [`svminnm`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svminnm[) | | FMINNM (vectors) | [`svminnm`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svminnm[) | | FMINNMP | [`svminnmp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svminnmp) | | FMINNMV | [`svminnmv`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svminnmv) | | FMINP | [`svminp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svminp) | | FMINV | [`svminv`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svminv) | | FMLA (indexed) | [`svmla`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmla[) | | FMLA (vectors) | [`svmla`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmla[) | | FMLALB (indexed) | [`svmlalb_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmlalb_lane) | | FMLALB (vectors) | [`svmlalb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmlalb[) | | FMLALT (indexed) | [`svmlalt_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmlalt_lane) | | FMLALT (vectors) | [`svmlalt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmlalt[) | | FMLS (indexed) | [`svmls_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmls_lane) | | FMLS (vectors) | [`svmls`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmls[) | | FMLSLB (indexed) | [`svmlslb_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmlslb_lane) | | FMLSLB (vectors) | [`svmlslb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmlslb[) | | FMLSLT (indexed) | [`svmlslt_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmlslt_lane) | | FMLSLT (vectors) | [`svmlslt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmlslt[) | | FMMLA | [`svmmla`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmmla) | | FMOV (immediate, predicated) | [`svdup`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svdup[_n]) | | FMOV (immediate, unpredicated) | [`svdup`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svdup[_n]) | | FMOV (zero, predicated) | [`svdup`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svdup[_n]) | | FMOV (zero, unpredicated) | [`svdup`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svdup[_n]) | | FMSB | [`svmsb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmsb) | | FMUL (immediate) | [`svmul`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmul[) | | FMUL (indexed) | [`svmul`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmul[) | | FMUL (vectors, predicated) | [`svmul`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmul[) | | FMUL (vectors, unpredicated) | [`svmul`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmul[) | | FMULX | [`svmulx`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svmulx) | | FNEG | [`svneg`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svneg) | | FNMAD | [`svnmad`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svnmad) | | FNMLA | [`svnmla`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svnmla) | | FNMLS | [`svnmls`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svnmls) | | FNMSB | [`svnmsb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svnmsb) | | FRECPE | [`svrecpe`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svrecpe) | | FRECPS | [`svrecps`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svrecps) | | FRECPX | [`svrecpx`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svrecpx) | | FRINTA | [`svrinta`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svrinta) | | FRINTI | [`svrinti`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svrinti) | | FRINTM | [`svrintm`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svrintm) | | FRINTN | [`svrintn`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svrintn) | | FRINTP | [`svrintp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svrintp) | | FRINTX | [`svrintx`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svrintx) | | FRINTZ | [`svrintz`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svrintz) | | FRSQRTE | [`svrsqrte`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svrsqrte) | | FRSQRTS | [`svrsqrts`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svrsqrts) | | FSCALE | [`svscale`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svscale) | | FSQRT | [`svsqrt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svsqrt) | | FSUB (immediate) | [`svsub`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svsub[) | | FSUB (vectors, predicated) | [`svsub`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svsub[) | | FSUB (vectors, unpredicated) | [`svsub`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svsub[) | | FSUBR (immediate) | [`svsubr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svsubr) | | FSUBR (vectors) | [`svsubr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svsubr) | | FTMAD | [`svtmad`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svtmad) | | FTSMUL | [`svtsmul`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svtsmul) | | FTSSEL | [`svtssel`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[float]&q=svtssel) | | HISTCNT | [`svhistcnt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svhistcnt) | | HISTSEG | [`svhistseg`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svhistseg) | | INCB | See [ADDPL, ADDVL, INC and DEC](#addpl-addvl-inc-and-dec) | | INCD (scalar) | See [ADDPL, ADDVL, INC and DEC](#addpl-addvl-inc-and-dec) | | INCD (vector) | See [ADDPL, ADDVL, INC and DEC](#addpl-addvl-inc-and-dec) | | INCH (scalar) | See [ADDPL, ADDVL, INC and DEC](#addpl-addvl-inc-and-dec) | | INCH (vector) | See [ADDPL, ADDVL, INC and DEC](#addpl-addvl-inc-and-dec) | | INCP (scalar) | See [ADDPL, ADDVL, INC and DEC](#addpl-addvl-inc-and-dec) | | INCP (vector) | See [ADDPL, ADDVL, INC and DEC](#addpl-addvl-inc-and-dec) | | INCW (scalar) | See [ADDPL, ADDVL, INC and DEC](#addpl-addvl-inc-and-dec) | | INCW (vector) | See [ADDPL, ADDVL, INC and DEC](#addpl-addvl-inc-and-dec) | | INDEX (immediate, scalar) | [`svindex`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svindex) | | INDEX (immediates) | [`svindex`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svindex) | | INDEX (scalar, immediate) | [`svindex`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svindex) | | INDEX (scalars) | [`svindex`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svindex) | | INSR (SIMD & FP scalar) | [`svinsr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svinsr) | | INSR (scalar) | [`svinsr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svinsr) | | LASTA (SIMD & FP scalar) | [`svlasta`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svlasta) | | LASTA (scalar) | [`svlasta`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svlasta) | | LASTB (SIMD & FP scalar) | [`svlastb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svlastb) | | LASTB (scalar) | [`svlastb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svlastb) | | LD1B (scalar plus immediate) | [`svld1_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[8]&q=svld1_vnum), [`svld1ub_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1ub_vnum) | | LD1B (scalar plus scalar) | [`svld1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[8]&q=svld1[), [`svld1ub`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#&q=svld1ub) | | LD1B (scalar plus vector) | [`svld1ub_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1ub_gather_[) | | LD1B (vector plus immediate) | [`svld1ub_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1ub_gather[) | | LD1D (scalar plus immediate) | [`svld1_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svld1_vnum) | | LD1D (scalar plus scalar) | [`svld1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svld1[) | | LD1D (scalar plus vector) | [`svld1_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svld1_gather_[) | | LD1D (vector plus immediate) | [`svld1_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svld1_gather[) | | LD1H (scalar plus immediate) | [`svld1_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[16]&q=svld1_vnum), [`svld1uh_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1uh_vnum) | | LD1H (scalar plus scalar) | [`svld1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[16]&q=svld1[), [`svld1uh`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#&q=svld1uh) | | LD1H (scalar plus vector) | [`svld1uh_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1uh_gather_[) | | LD1H (vector plus immediate) | [`svld1uh_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1uh_gather[) | | LD1RB | See [SVE LD1R instructions](#sve-ld1r-instructions) | | LD1RD | See [SVE LD1R instructions](#sve-ld1r-instructions) | | LD1RH | See [SVE LD1R instructions](#sve-ld1r-instructions) | | LD1ROB (scalar plus immediate) | [`svld1ro`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[8]&q=svld1ro) | | LD1ROB (scalar plus scalar) | [`svld1ro`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[8]&q=svld1ro) | | LD1ROD (scalar plus immediate) | [`svld1ro`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svld1ro) | | LD1ROD (scalar plus scalar) | [`svld1ro`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svld1ro) | | LD1ROH (scalar plus immediate) | [`svld1ro`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[16]&q=svld1ro) | | LD1ROH (scalar plus scalar) | [`svld1ro`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[16]&q=svld1ro) | | LD1ROW (scalar plus immediate) | [`svld1ro`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svld1ro) | | LD1ROW (scalar plus scalar) | [`svld1ro`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svld1ro) | | LD1RQB (scalar plus immediate) | [`svld1rq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[8]&q=svld1rq), [`svdupq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[8]&q=svdupq) | | LD1RQB (scalar plus scalar) | [`svld1rq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[8]&q=svld1rq), [`svdupq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[8]&q=svdupq) | | LD1RQD (scalar plus immediate) | [`svld1rq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svld1rq), [`svdupq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svdupq) | | LD1RQD (scalar plus scalar) | [`svld1rq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svld1rq), [`svdupq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svdupq) | | LD1RQH (scalar plus immediate) | [`svld1rq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[16]&q=svld1rq), [`svdupq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[16]&q=svdupq) | | LD1RQH (scalar plus scalar) | [`svld1rq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[16]&q=svld1rq), [`svdupq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[16]&q=svdupq) | | LD1RQW (scalar plus immediate) | [`svld1rq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svld1rq), [`svdupq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svdupq) | | LD1RQW (scalar plus scalar) | [`svld1rq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svld1rq), [`svdupq`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svdupq) | | LD1RSB | See [SVE LD1R instructions](#sve-ld1r-instructions) | | LD1RSH | See [SVE LD1R instructions](#sve-ld1r-instructions) | | LD1RSW | See [SVE LD1R instructions](#sve-ld1r-instructions) | | LD1RW | See [SVE LD1R instructions](#sve-ld1r-instructions) | | LD1SB (scalar plus immediate) | [`svld1sb_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1sb_vnum) | | LD1SB (scalar plus scalar) | [`svld1sb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1sb) | | LD1SB (scalar plus vector) | [`svld1sb_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1sb_gather_[) | | LD1SB (vector plus immediate) | [`svld1sb_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1sb_gather[) | | LD1SH (scalar plus immediate) | [`svld1sh_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1sh_vnum) | | LD1SH (scalar plus scalar) | [`svld1sh`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1sh) | | LD1SH (scalar plus vector) | [`svld1sh_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1sh_gather_[) | | LD1SH (vector plus immediate) | [`svld1sh_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1sh_gather[) | | LD1SW (scalar plus immediate) | [`svld1sw_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1sw_vnum) | | LD1SW (scalar plus scalar) | [`svld1sw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1sw) | | LD1SW (scalar plus vector) | [`svld1sw_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1sw_gather_[) | | LD1SW (vector plus immediate) | [`svld1sw_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1sw_gather[) | | LD1W (scalar plus immediate) | [`svld1_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svld1_vnum), [`svld1uw_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1uw_vnum) | | LD1W (scalar plus scalar) | [`svld1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svld1[), [`svld1uw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#&q=svld1uw) | | LD1W (scalar plus vector) | [`svld1_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svld1_gather_[), [`svld1uw_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1uw_gather_[) | | LD1W (vector plus immediate) | [`svld1_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svld1_gather[), [`svld1uw_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svld1uw_gather[) | | LD2B (scalar plus immediate) | [`svld2_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[8]&q=svld2_vnum) | | LD2B (scalar plus scalar) | [`svld2`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[8]&q=svld2[) | | LD2D (scalar plus immediate) | [`svld2_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svld2_vnum) | | LD2D (scalar plus scalar) | [`svld2`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svld2[) | | LD2H (scalar plus immediate) | [`svld2_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[16]&q=svld2_vnum) | | LD2H (scalar plus scalar) | [`svld2`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[16]&q=svld2[) | | LD2W (scalar plus immediate) | [`svld2_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svld2_vnum) | | LD2W (scalar plus scalar) | [`svld2`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svld2[) | | LD3B (scalar plus immediate) | [`svld3_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[8]&q=svld3_vnum) | | LD3B (scalar plus scalar) | [`svld3`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[8]&q=svld3[) | | LD3D (scalar plus immediate) | [`svld3_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svld3_vnum) | | LD3D (scalar plus scalar) | [`svld3`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svld3[) | | LD3H (scalar plus immediate) | [`svld3_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[16]&q=svld3_vnum) | | LD3H (scalar plus scalar) | [`svld3`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[16]&q=svld3[) | | LD3W (scalar plus immediate) | [`svld3_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svld3_vnum) | | LD3W (scalar plus scalar) | [`svld3`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svld3[) | | LD4B (scalar plus immediate) | [`svld4_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[8]&q=svld4_vnum) | | LD4B (scalar plus scalar) | [`svld4`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[8]&q=svld4[) | | LD4D (scalar plus immediate) | [`svld4_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svld4_vnum) | | LD4D (scalar plus scalar) | [`svld4`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svld4[) | | LD4H (scalar plus immediate) | [`svld4_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[16]&q=svld4_vnum) | | LD4H (scalar plus scalar) | [`svld4`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[16]&q=svld4[) | | LD4W (scalar plus immediate) | [`svld4_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svld4_vnum) | | LD4W (scalar plus scalar) | [`svld4`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svld4[) | | LDFF1B (scalar plus scalar) | [`svldff1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[8]&q=svldff1[), [`svldff1ub`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldff1ub) | | LDFF1B (scalar plus vector) | [`svldff1ub_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldff1ub_gather_[) | | LDFF1B (vector plus immediate) | [`svldff1ub_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldff1ub_gather[) | | LDFF1D (scalar plus scalar) | [`svldff1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svldff1[) | | LDFF1D (scalar plus vector) | [`svldff1_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svldff1_gather_[) | | LDFF1D (vector plus immediate) | [`svldff1_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svldff1_gather[) | | LDFF1H (scalar plus scalar) | [`svldff1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[16]&q=svldff1[), [`svldff1uh`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldff1uh) | | LDFF1H (scalar plus vector) | [`svldff1uh_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldff1uh_gather_[) | | LDFF1H (vector plus immediate) | [`svldff1uh_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldff1uh_gather[) | | LDFF1SB (scalar plus scalar) | [`svldff1sb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldff1sb) | | LDFF1SB (scalar plus vector) | [`svldff1sb_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldff1sb_gather_[) | | LDFF1SB (vector plus immediate) | [`svldff1sb_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldff1sb_gather[) | | LDFF1SH (scalar plus scalar) | [`svldff1sh`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldff1sh) | | LDFF1SH (scalar plus vector) | [`svldff1sh_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldff1sh_gather_[) | | LDFF1SH (vector plus immediate) | [`svldff1sh_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldff1sh_gather[) | | LDFF1SW (scalar plus scalar) | [`svldff1sw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldff1sw) | | LDFF1SW (scalar plus vector) | [`svldff1sw_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldff1sw_gather_[) | | LDFF1SW (vector plus immediate) | [`svldff1sw_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldff1sw_gather[) | | LDFF1W (scalar plus scalar) | [`svldff1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svldff1[), [`svldff1uw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldff1uw) | | LDFF1W (scalar plus vector) | [`svldff1_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svldff1_gather_[), [`svldff1uw_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldff1uw_gather_[) | | LDFF1W (vector plus immediate) | [`svldff1_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svldff1_gather[), [`svldff1uw_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldff1uw_gather[) | | LDNF1B | [`svldnf1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[8]&q=svldnf1[), [`svldnf1ub`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldnf1ub) | | LDNF1D | [`svldnf1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svldnf1[) | | LDNF1H | [`svldnf1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[16]&q=svldnf1[), [`svldnf1uh`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldnf1uh) | | LDNF1SB | [`svldnf1sb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldnf1sb) | | LDNF1SH | [`svldnf1sh`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldnf1sh) | | LDNF1SW | [`svldnf1sw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldnf1sw) | | LDNF1W | [`svldnf1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svldnf1[), [`svldnf1uw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldnf1uw) | | LDNT1B (scalar plus immediate) | [`svldnt1_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[8]&q=svldnt1_vnum) | | LDNT1B (scalar plus scalar) | [`svldnt1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[8]&q=svldnt1[) | | LDNT1B (vector plus scalar) | [`svldnt1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldnt1_gather), [`svldnt1ub`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldnt1ub) | | LDNT1D (scalar plus immediate) | [`svldnt1_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svldnt1_vnum) | | LDNT1D (scalar plus scalar) | [`svldnt1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[64]&q=svldnt1[) | | LDNT1D (vector plus scalar) | [`svldnt1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldnt1_gather) | | LDNT1H (scalar plus immediate) | [`svldnt1_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[16]&q=svldnt1_vnum) | | LDNT1H (scalar plus scalar) | [`svldnt1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[16]&q=svldnt1[) | | LDNT1H (vector plus scalar) | [`svldnt1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldnt1_gather), [`svldnt1uh`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldnt1uh) | | LDNT1SB | [`svldnt1sb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldnt1sb) | | LDNT1SH | [`svldnt1sh`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldnt1sh) | | LDNT1SW | [`svldnt1sw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldnt1sw) | | LDNT1W (scalar plus immediate) | [`svldnt1_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svldnt1_vnum) | | LDNT1W (scalar plus scalar) | [`svldnt1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[32]&q=svldnt1[) | | LDNT1W (vector plus scalar) | [`svldnt1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldnt1_gather), [`svldnt1uw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svldnt1uw) | | LDR (predicate) | See [SVE LDR and STR](#sve-ldr-and-str) | | LDR (vector) | See [SVE LDR and STR](#sve-ldr-and-str) | | LSL (immediate, predicated) | [`svlsl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svlsl[) | | LSL (immediate, unpredicated) | [`svlsl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svlsl[) | | LSL (vectors) | [`svlsl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svlsl[) | | LSL (wide elements, predicated) | [`svlsl_wide`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svlsl_wide) | | LSL (wide elements, unpredicated) | [`svlsl_wide`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svlsl_wide) | | LSLR | [`svlsl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svlsl[) (optimization of `_x` forms) | | LSR (immediate, predicated) | [`svlsr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svlsr[) | | LSR (immediate, unpredicated) | [`svlsr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svlsr[) | | LSR (vectors) | [`svlsr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svlsr[) | | LSR (wide elements, predicated) | [`svlsr_wide`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svlsr_wide) | | LSR (wide elements, unpredicated) | [`svlsr_wide`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svlsr_wide) | | LSRR | [`svlsr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svlsr[) (optimization of `_x` forms) | | MAD | [`svmad`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svmad) | | MATCH | [`svmatch`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svmatch) | | MLA (indexed) | [`svmla_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svmla_lane) | | MLA (vectors) | [`svmla`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svmla[) | | MLS (indexed) | [`svmls_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svmls_lane) | | MLS (vectors) | [`svmls`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svmls[) | | MOV (SIMD & FP scalar, predicated) | [`svdup`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdup[_n]) | | MOV (SIMD & FP scalar, unpredicated) | [`svdup`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdup[_n]) | | MOV (bitmask immediate) | [`svdup`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdup[_n]) | | MOV (immediate, predicated) | [`svdup`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdup[_n]) | | MOV (immediate, unpredicated) | [`svdup`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdup[_n]) | | MOV (predicate, predicated, merging) | [`svsel`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=svsel) | | MOV (predicate, predicated, zeroing) | [`svmov`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svmov) | | MOV (predicate, unpredicated) | See [SVE MOV](#sve-mov) | | MOV (scalar, predicated) | [`svdup`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdup[_n]) | | MOV (scalar, unpredicated) | [`svdup`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdup[_n]) | | MOV (vector, predicated) | [`svsel`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int,float,bfloat]&q=svsel) | | MOV (vector, unpredicated) | See [SVE MOV](#sve-mov) | | MOVPRFX (predicated) | See [MOVPRFX](#movprfx) | | MOVPRFX (unpredicated) | See [MOVPRFX](#movprfx) | | MOVS (predicated) | [`svmov`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svmov) | | MOVS (unpredicated) | See [SVE MOV](#sve-mov) | | MSB | [`svmsb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svmsb) | | MUL (immediate) | [`svmul`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svmul[) | | MUL (indexed) | [`svmul_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svmul_lane) | | MUL (vectors, predicated) | [`svmul`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svmul[) | | MUL (vectors, unpredicated) | [`svmul`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svmul[) | | NAND | [`svnand`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svnand) | | NANDS | [`svnand`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svnand) | | NBSL | [`svnbsl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svnbsl) | | NEG | [`svneg`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svneg) | | NMATCH | [`svnmatch`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svnmatch) | | NOR | [`svnor`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svnor) | | NORS | [`svnor`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svnor) | | NOT (predicate) | [`svnot`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=svnot) | | NOT (vector) | [`svnot`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svnot) | | NOTS | [`svnot`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=svnot) | | ORN (immediate) | [`svorr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int,uint]&q=svorr[) | | ORN (predicates) | [`svorn`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svorn) | | ORNS | [`svorn`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svorn) | | ORR (immediate) | [`svorr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int,uint]&q=svorr[) | | ORR (predicates) | [`svorr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=svorr) | | ORR (vectors, predicated) | [`svorr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int,uint]&q=svorr[) | | ORR (vectors, unpredicated) | [`svorr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int,uint]&q=svorr[) | | ORRS | [`svorr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=svorr) | | ORV | [`svorv`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svorv) | | PFALSE | [`svpfalse`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svpfalse) | | PFIRST | [`svpfirst`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svpfirst) | | PMUL | [`svpmul`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svpmul[) | | PMULLB | [`svpmullb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svpmullb[), [`svpmullb_pair`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svpmullb_pair) | | PMULLT | [`svpmullt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svpmullt[), [`svpmullt_pair`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svpmullt_pair) | | PNEXT | [`svpnext`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svpnext) | | PRFB (scalar plus immediate) | [`svprfb_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svprfb_vnum) | | PRFB (scalar plus scalar) | [`svprfb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svprfb) | | PRFB (scalar plus vector) | [`svprfb_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svprfb_gather_[) | | PRFB (vector plus immediate) | [`svprfb_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svprfb_gather[) | | PRFD (scalar plus immediate) | [`svprfd_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svprfd_vnum) | | PRFD (scalar plus scalar) | [`svprfd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svprfd) | | PRFD (scalar plus vector) | [`svprfd_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svprfd_gather_[) | | PRFD (vector plus immediate) | [`svprfd_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svprfd_gather[) | | PRFH (scalar plus immediate) | [`svprfh_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svprfh_vnum) | | PRFH (scalar plus scalar) | [`svprfh`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svprfh) | | PRFH (scalar plus vector) | [`svprfh_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svprfh_gather_[) | | PRFH (vector plus immediate) | [`svprfh_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svprfh_gather[) | | PRFW (scalar plus immediate) | [`svprfw_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svprfw_vnum) | | PRFW (scalar plus scalar) | [`svprfw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svprfw) | | PRFW (scalar plus vector) | [`svprfw_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svprfw_gather_[) | | PRFW (vector plus immediate) | [`svprfw_gather`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svprfw_gather[) | | PTEST | [`svptest`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svptest) | | PTRUE | [`svptrue`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svptrue) | | PTRUES | [`svptrue`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svptrue) | | PUNPKHI | [`svunpkhi`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=svunpkhi) | | PUNPKLO | [`svunpklo`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=svunpklo) | | RADDHNB | [`svraddhnb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svraddhnb) | | RADDHNT | [`svraddhnt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svraddhnt) | | RAX1 | [`svrax1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svrax1) | | RBIT | [`svrbit`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svrbit) | | RDFFR (predicated) | [`svrdffr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svrdffr) | | RDFFR (unpredicated) | [`svrdffr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svrdffr) | | RDFFRS | [`svrdffr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svrdffr) | | RDVL | See [RDVL](#rdvl) | | REV (predicate) | [`svrev`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=svrev) | | REV (vector) | [`svrev`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int,float,bfloat]&q=svrev) | | REVB | [`svrevb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svrevb) | | REVH | [`svrevh`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svrevh) | | REVW | [`svrevw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svrevw) | | RSHRNB | [`svrshrnb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svrshrnb) | | RSHRNT | [`svrshrnt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svrshrnt) | | RSUBHNB | [`svrsubhnb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svrsubhnb) | | RSUBHNT | [`svrsubhnt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svrsubhnt) | | SABA | [`svaba`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svaba[) | | SABALB | [`svabalb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svabalb) | | SABALT | [`svabalt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svabalt) | | SABD | [`svabd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svabd[) | | SABDLB | [`svabdlb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svabdlb) | | SABDLT | [`svabdlt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svabdlt) | | SADALP | [`svadalp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svadalp) | | SADDLB | [`svaddlb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svaddlb[) | | SADDLBT | [`svaddlbt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svaddlbt) | | SADDLT | [`svaddlt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svaddlt) | | SADDV | [`svaddv`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svaddv) | | SADDWB | [`svaddwb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svaddwb) | | SADDWT | [`svaddwt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svaddwt) | | SBCLB | [`svsbclb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svsbclb) | | SBCLT | [`svsbclt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svsbclt) | | SCVTF | [`svcvt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcvt_) | | SDIV | [`svdiv`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svdiv[) | | SDIVR | [`svdivr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svdivr) | | SDOT (indexed) | [`svdot_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svdot_lane) | | SDOT (vectors) | [`svdot`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svdot[) | | SEL (predicates) | [`svsel`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=svsel) | | SEL (vectors) | [`svsel`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int,float,bfloat]&q=svsel) | | SETFFR | [`svsetffr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svsetffr) | | SHADD | [`svhadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svhadd) | | SHRNB | [`svshrnb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svshrnb) | | SHRNT | [`svshrnt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svshrnt) | | SHSUB | [`svhsub`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svhsub[) | | SHSUBR | [`svhsubr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svhsubr) | | SLI | [`svsli`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svsli) | | SM4E | [`svsm4e`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svsm4e[) | | SM4EKEY | [`svsm4ekey`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svsm4ekey) | | SMAX (immediate) | [`svmax`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmax[) | | SMAX (vectors) | [`svmax`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmax[) | | SMAXP | [`svmaxp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmaxp) | | SMAXV | [`svmaxv`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmaxv) | | SMIN (immediate) | [`svmin`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmin[) | | SMIN (vectors) | [`svmin`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmin[) | | SMINP | [`svminp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svminp) | | SMINV | [`svminv`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svminv) | | SMLALB (indexed) | [`svmlalb_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmlalb_lane) | | SMLALB (vectors) | [`svmlalb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmlalb[) | | SMLALT (indexed) | [`svmlalt_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmlalt_lane) | | SMLALT (vectors) | [`svmlalt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmlalt[) | | SMLSLB (indexed) | [`svmlslb_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmlslb_lane) | | SMLSLB (vectors) | [`svmlslb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmlslb[) | | SMLSLT (indexed) | [`svmlslt_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmlslt_lane) | | SMLSLT (vectors) | [`svmlslt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmlslt[) | | SMMLA | [`svmmla`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmmla) | | SMULH (predicated) | [`svmulh`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmulh) | | SMULH (unpredicated) | [`svmulh`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmulh) | | SMULLB (indexed) | [`svmullb_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmullb_lane) | | SMULLB (vectors) | [`svmullb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmullb[) | | SMULLT (indexed) | [`svmullt_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmullt_lane) | | SMULLT (vectors) | [`svmullt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmullt[) | | SPLICE | [`svsplice`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svsplice) | | SQABS | [`svqabs`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqabs) | | SQADD (immediate) | [`svqadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqadd) | | SQADD (vectors, predicated) | [`svqadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqadd) | | SQADD (vectors, unpredicated) | [`svqadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqadd) | | SQCADD | [`svqcadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqcadd) | | SQDECB | [`svqdecb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdecb) | | SQDECD (scalar) | [`svqdecd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdecd) | | SQDECD (vector) | [`svqdecd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdecd) | | SQDECH (scalar) | [`svqdech`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdech) | | SQDECH (vector) | [`svqdech`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdech) | | SQDECP (scalar) | [`svqdecp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdecp) | | SQDECP (vector) | [`svqdecp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdecp) | | SQDECW (scalar) | [`svqdecw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdecw) | | SQDECW (vector) | [`svqdecw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdecw) | | SQDMLALB (indexed) | [`svqdmlalb_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdmlalb_lane) | | SQDMLALB (vectors) | [`svqdmlalb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdmlalb[) | | SQDMLALBT | [`svqdmlalbt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdmlalbt) | | SQDMLALT (indexed) | [`svqdmlalt_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdmlalt_lane) | | SQDMLALT (vectors) | [`svqdmlalt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdmlalt[) | | SQDMLSLB (indexed) | [`svqdmlslb_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdmlslb_lane) | | SQDMLSLB (vectors) | [`svqdmlslb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdmlslb[) | | SQDMLSLBT | [`svqdmlslbt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdmlslbt) | | SQDMLSLT (indexed) | [`svqdmlslt_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdmlslt_lane) | | SQDMLSLT (vectors) | [`svqdmlslt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdmlslt[) | | SQDMULH (indexed) | [`svqdmulh_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdmulh_lane) | | SQDMULH (vectors) | [`svqdmulh`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdmulh[) | | SQDMULLB (indexed) | [`svqdmullb_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdmullb_lane) | | SQDMULLB (vectors) | [`svqdmullb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdmullb[) | | SQDMULLT (indexed) | [`svqdmullt_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdmullt_lane) | | SQDMULLT (vectors) | [`svqdmullt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqdmullt[) | | SQINCB | [`svqincb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqincb) | | SQINCD (scalar) | [`svqincd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqincd) | | SQINCD (vector) | [`svqincd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqincd) | | SQINCH (scalar) | [`svqinch`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqinch) | | SQINCH (vector) | [`svqinch`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqinch) | | SQINCP (scalar) | [`svqincp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqincp) | | SQINCP (vector) | [`svqincp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqincp) | | SQINCW (scalar) | [`svqincw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqincw) | | SQINCW (vector) | [`svqincw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqincw) | | SQNEG | [`svqneg`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqneg) | | SQRDCMLAH (indexed) | [`svqrdcmlah_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqrdcmlah_lane) | | SQRDCMLAH (vectors) | [`svqrdcmlah`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqrdcmlah[) | | SQRDMLAH (indexed) | [`svqrdmlah_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqrdmlah_lane) | | SQRDMLAH (vectors) | [`svqrdmlah`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqrdmlah[) | | SQRDMLSH (indexed) | [`svqrdmlsh_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqrdmlsh_lane) | | SQRDMLSH (vectors) | [`svqrdmlsh`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqrdmlsh[) | | SQRDMULH (indexed) | [`svqrdmulh_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqrdmulh_lane) | | SQRDMULH (vectors) | [`svqrdmulh`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqrdmulh[) | | SQRSHL | [`svqrshl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqrshl[) | | SQRSHLR | [`svqrshl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqrshl[) | | SQRSHRNB | [`svqrshrnb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqrshrnb) | | SQRSHRNT | [`svqrshrnt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqrshrnt) | | SQRSHRUNB | [`svqrshrunb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svqrshrunb) | | SQRSHRUNT | [`svqrshrunt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svqrshrunt) | | SQSHL (immediate) | [`svqshl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqshl[) | | SQSHL (vectors) | [`svqshl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqshl[) | | SQSHLR | [`svqshl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqshl[) | | SQSHLU | [`svqshlu`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#&q=svqshlu) | | SQSHRNB | [`svqshrnb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqshrnb) | | SQSHRNT | [`svqshrnt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqshrnt) | | SQSHRUNB | [`svqshrunb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svqshrunb) | | SQSHRUNT | [`svqshrunt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svqshrunt) | | SQSUB (immediate) | [`svqsub`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqsub[) | | SQSUB (vectors, predicated) | [`svqsub`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqsub[) | | SQSUB (vectors, unpredicated) | [`svqsub`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqsub[) | | SQSUBR | [`svqsubr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqsubr) | | SQXTNB | [`svqxtnb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqxtnb) | | SQXTNT | [`svqxtnt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svqxtnt) | | SQXTUNB | [`svqxtunb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svqxtunb) | | SQXTUNT | [`svqxtunt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svqxtunt) | | SRHADD | [`svrhadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svrhadd) | | SRI | [`svsri`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svsri) | | SRSHL | [`svrshl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svrshl) | | SRSHLR | [`svrshl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svrshl) | | SRSHR | [`svrshr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svrshr[) | | SRSRA | [`svrsra`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svrsra) | | SSHLLB | [`svshllb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svshllb), [`svmovlb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmovlb) | | SSHLLT | [`svshllt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svshllt), [`svmovlt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svmovlt) | | SSRA | [`svsra`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svsra) | | SSUBLB | [`svsublb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svsublb[) | | SSUBLBT | [`svsublbt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svsublbt) | | SSUBLT | [`svsublt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svsublt[) | | SSUBLTB | [`svsubltb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svsubltb) | | SSUBWB | [`svsubwb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svsubwb) | | SSUBWT | [`svsubwt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svsubwt) | | ST1B (scalar plus immediate) | [`svst1_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1_vnum), [`svst1b_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1b_vnum) | | ST1B (scalar plus scalar) | [`svst1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1[), [`svst1b`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1b) | | ST1B (scalar plus vector) | [`svst1b_scatter`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1b_scatter_[) | | ST1B (vector plus immediate) | [`svst1b_scatter`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1b_scatter[) | | ST1D (scalar plus immediate) | [`svst1_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1_vnum) | | ST1D (scalar plus scalar) | [`svst1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1[) | | ST1D (scalar plus vector) | [`svst1_scatter`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1_scatter_[) | | ST1D (vector plus immediate) | [`svst1_scatter`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1_scatter[) | | ST1H (scalar plus immediate) | [`svst1_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1_vnum), [`svst1h_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1h_vnum) | | ST1H (scalar plus scalar) | [`svst1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1[), [`svst1h`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1h) | | ST1H (scalar plus vector) | [`svst1h_scatter`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1h_scatter_[) | | ST1H (vector plus immediate) | [`svst1h_scatter`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1h_scatter[) | | ST1W (scalar plus immediate) | [`svst1_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1_vnum), [`svst1w_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1w_vnum) | | ST1W (scalar plus scalar) | [`svst1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1[), [`svst1w`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1w) | | ST1W (scalar plus vector) | [`svst1_scatter`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1_scatter_[), [`svst1w_scatter`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1w_scatter_[) | | ST1W (vector plus immediate) | [`svst1_scatter`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1_scatter[), [`svst1w_scatter`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1w_scatter[) | | ST2B (scalar plus immediate) | [`svst2_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst2_vnum) | | ST2B (scalar plus scalar) | [`svst2`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst2[) | | ST2D (scalar plus immediate) | [`svst2_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst2_vnum) | | ST2D (scalar plus scalar) | [`svst2`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst2[) | | ST2H (scalar plus immediate) | [`svst2_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst2_vnum) | | ST2H (scalar plus scalar) | [`svst2`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst2[) | | ST2W (scalar plus immediate) | [`svst2_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst2_vnum) | | ST2W (scalar plus scalar) | [`svst2`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst2[) | | ST3B (scalar plus immediate) | [`svst3_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst3_vnum) | | ST3B (scalar plus scalar) | [`svst3`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst3[) | | ST3D (scalar plus immediate) | [`svst3_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst3_vnum) | | ST3D (scalar plus scalar) | [`svst3`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst3[) | | ST3H (scalar plus immediate) | [`svst3_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst3_vnum) | | ST3H (scalar plus scalar) | [`svst3`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst3[) | | ST3W (scalar plus immediate) | [`svst3_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst3_vnum) | | ST3W (scalar plus scalar) | [`svst3`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst3[) | | ST4B (scalar plus immediate) | [`svst4_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst4_vnum) | | ST4B (scalar plus scalar) | [`svst4`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst4[) | | ST4D (scalar plus immediate) | [`svst4_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst4_vnum) | | ST4D (scalar plus scalar) | [`svst4`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst4[) | | ST4H (scalar plus immediate) | [`svst4_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst4_vnum) | | ST4H (scalar plus scalar) | [`svst4`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst4[) | | ST4W (scalar plus immediate) | [`svst4_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst4_vnum) | | ST4W (scalar plus scalar) | [`svst4`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst4[) | | STNT1B (scalar plus immediate) | [`svstnt1_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svstnt1_vnum) | | STNT1B (scalar plus scalar) | [`svstnt1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svstnt1[) | | STNT1B (vector plus scalar) | [`svstnt1_scatter`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svstnt1_scatter), [`svstnt1b`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svstnt1b) | | STNT1D (scalar plus immediate) | [`svstnt1_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svstnt1_vnum) | | STNT1D (scalar plus scalar) | [`svstnt1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svstnt1[) | | STNT1D (vector plus scalar) | [`svstnt1_scatter`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svstnt1_scatter) | | STNT1H (scalar plus immediate) | [`svstnt1_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svstnt1_vnum) | | STNT1H (scalar plus scalar) | [`svstnt1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svstnt1[) | | STNT1H (vector plus scalar) | [`svstnt1_scatter`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svstnt1_scatter), [`svstnt1h`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svstnt1h) | | STNT1W (scalar plus immediate) | [`svstnt1_vnum`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svstnt1_vnum) | | STNT1W (scalar plus scalar) | [`svstnt1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svstnt1[) | | STNT1W (vector plus scalar) | [`svstnt1_scatter`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svstnt1_scatter), [`svstnt1w`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svstnt1w) | | STR (predicate) | See [SVE LDR and STR](#sve-ldr-and-str) | | STR (vector) | See [SVE LDR and STR](#sve-ldr-and-str) | | SUB (immediate) | [`svsub`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svsub[) | | SUB (vectors, predicated) | [`svsub`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svsub[) | | SUB (vectors, unpredicated) | [`svsub`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svsub[) | | SUBHNB | [`svsubhnb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svsubhnb) | | SUBHNT | [`svsubhnt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svsubhnt) | | SUBR (immediate) | [`svsubr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svsubr) | | SUBR (vectors) | [`svsubr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svsubr) | | SUDOT | [`svsudot_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svsudot_lane) | | SUNPKHI | [`svunpkhi`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svunpkhi) | | SUNPKLO | [`svunpklo`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svunpklo) | | SUQADD | [`svuqadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svuqadd) | | SXTB | [`svextb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svextb) | | SXTH | [`svexth`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svexth) | | SXTW | [`svextw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svextw) | | TBL | [`svtbl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svtbl[), [`svdup_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdup_lane) | | TBX | [`svtbx`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svtbx) | | TRN1 (predicates) | [`svtrn1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=svtrn1) | | TRN1 (vectors) | [`svtrn1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int,float,bfloat]&q=svtrn1) | | TRN2 (predicates) | [`svtrn2`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=svtrn2) | | TRN2 (vectors) | [`svtrn2`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int,float,bfloat]&q=svtrn2) | | UABA | [`svaba`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svaba[) | | UABALB | [`svabalb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svabalb) | | UABALT | [`svabalt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svabalt) | | UABD | [`svabd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svabd[) | | UABDLB | [`svabdlb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svabdlb) | | UABDLT | [`svabdlt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svabdlt) | | UADALP | [`svadalp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svadalp) | | UADDLB | [`svaddlb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svaddlb[) | | UADDLT | [`svaddlt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svaddlt) | | UADDV | [`svaddv`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int]&q=svaddv) | | UADDWB | [`svaddwb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svaddwb) | | UADDWT | [`svaddwt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svaddwt) | | UCVTF | [`svcvt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svcvt_) | | UDIV | [`svdiv`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svdiv[) | | UDIVR | [`svdivr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svdivr) | | UDOT (indexed) | [`svdot_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svdot_lane) | | UDOT (vectors) | [`svdot`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svdot[) | | UHADD | [`svhadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svhadd) | | UHSUB | [`svhsub`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svhsub[) | | UHSUBR | [`svhsubr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svhsubr) | | UMAX (immediate) | [`svmax`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmax[) | | UMAX (vectors) | [`svmax`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmax[) | | UMAXP | [`svmaxp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmaxp) | | UMAXV | [`svmaxv`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmaxv) | | UMIN (immediate) | [`svmin`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmin[) | | UMIN (vectors) | [`svmin`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmin[) | | UMINP | [`svminp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svminp) | | UMINV | [`svminv`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svminv) | | UMLALB (indexed) | [`svmlalb_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmlalb_lane) | | UMLALB (vectors) | [`svmlalb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmlalb[) | | UMLALT (indexed) | [`svmlalt_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmlalt_lane) | | UMLALT (vectors) | [`svmlalt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmlalt[) | | UMLSLB (indexed) | [`svmlslb_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmlslb_lane) | | UMLSLB (vectors) | [`svmlslb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmlslb[) | | UMLSLT (indexed) | [`svmlslt_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmlslt_lane) | | UMLSLT (vectors) | [`svmlslt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmlslt[) | | UMMLA | [`svmmla`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmmla) | | UMULH (predicated) | [`svmulh`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmulh) | | UMULH (unpredicated) | [`svmulh`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmulh) | | UMULLB (indexed) | [`svmullb_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmullb_lane) | | UMULLB (vectors) | [`svmullb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmullb[) | | UMULLT (indexed) | [`svmullt_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmullt_lane) | | UMULLT (vectors) | [`svmullt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmullt[) | | UQADD (immediate) | [`svqadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqadd[) | | UQADD (vectors, predicated) | [`svqadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqadd) | | UQADD (vectors, unpredicated) | [`svqadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqadd[) | | UQDECB | [`svqdecb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqdecb) | | UQDECD (scalar) | [`svqdecd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqdecd) | | UQDECD (vector) | [`svqdecd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqdecd) | | UQDECH (scalar) | [`svqdech`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqdech) | | UQDECH (vector) | [`svqdech`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqdech) | | UQDECP (scalar) | [`svqdecp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqdecp) | | UQDECP (vector) | [`svqdecp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqdecp) | | UQDECW (scalar) | [`svqdecw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqdecw) | | UQDECW (vector) | [`svqdecw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqdecw) | | UQINCB | [`svqincb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqincb) | | UQINCD (scalar) | [`svqincd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqincd) | | UQINCD (vector) | [`svqincd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqincd) | | UQINCH (scalar) | [`svqinch`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqinch) | | UQINCH (vector) | [`svqinch`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqinch) | | UQINCP (scalar) | [`svqincp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqincp) | | UQINCP (vector) | [`svqincp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqincp) | | UQINCW (scalar) | [`svqincw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqincw) | | UQINCW (vector) | [`svqincw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqincw) | | UQRSHL | [`svqrshl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqrshl[) | | UQRSHLR | [`svqrshl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqrshl[) | | UQRSHRNB | [`svqrshrnb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqrshrnb) | | UQRSHRNT | [`svqrshrnt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqrshrnt) | | UQSHL (immediate) | [`svqshl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqshl[) | | UQSHL (vectors) | [`svqshl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqshl[) | | UQSHLR | [`svqshl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqshl[) | | UQSHRNB | [`svqshrnb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqshrnb) | | UQSHRNT | [`svqshrnt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqshrnt) | | UQSUB (immediate) | [`svqsub`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqsub[) | | UQSUB (vectors, predicated) | [`svqsub`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqsub[) | | UQSUB (vectors, unpredicated) | [`svqsub`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqsub[) | | UQSUBR | [`svqsubr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqsubr) | | UQXTNB | [`svqxtnb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqxtnb) | | UQXTNT | [`svqxtnt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svqxtnt) | | URECPE | [`svrecpe`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svrecpe) | | URHADD | [`svrhadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svrhadd) | | URSHL | [`svrshl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svrshl) | | URSHLR | [`svrshl`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svrshl) | | URSHR | [`svrshr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svrshr[) | | URSQRTE | [`svrsqrte`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svrsqrte) | | URSRA | [`svrsra`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svrsra) | | USDOT (indexed) | [`svusdot_lane`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svusdot_lane) | | USDOT (vectors) | [`svusdot`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svusdot[), [`svsudot`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svsudot[) | | USHLLB | [`svshllb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svshllb), [`svmovlb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmovlb) | | USHLLT | [`svshllt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svshllt), [`svmovlt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svmovlt) | | USMMLA | [`svusmmla`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svusmmla) | | USQADD | [`svsqadd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svsqadd) | | USRA | [`svsra`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svsra) | | USUBLB | [`svsublb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svsublb[) | | USUBLT | [`svsublt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svsublt[) | | USUBWB | [`svsubwb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svsubwb) | | USUBWT | [`svsubwt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svsubwt) | | UUNPKHI | [`svunpkhi`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svunpkhi) | | UUNPKLO | [`svunpklo`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svunpklo) | | UXTB | [`svextb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svextb) | | UXTH | [`svexth`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svexth) | | UXTW | [`svextw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svextw) | | UZP1 (predicates) | [`svuzp1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=svuzp1) | | UZP1 (vectors) | [`svuzp1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int,float,bfloat]&q=svuzp1) | | UZP2 (predicates) | [`svuzp2`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=svuzp2) | | UZP2 (vectors) | [`svuzp2`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int,float,bfloat]&q=svuzp2) | | WHILEGE | [`svwhilege`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svwhilege) | | WHILEGT | [`svwhilegt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svwhilegt) | | WHILEHI | [`svwhilegt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svwhilegt) | | WHILEHS | [`svwhilege`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svwhilege) | | WHILELE | [`svwhilele`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svwhilele) | | WHILELO | [`svwhilelt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svwhilelt) | | WHILELS | [`svwhilele`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint]&q=svwhilele) | | WHILELT | [`svwhilelt`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[int]&q=svwhilelt) | | WHILERW | [`svwhilerw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svwhilerw) | | WHILEWR | [`svwhilewr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svwhilewr) | | WRFFR | [`svwrffr`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svwrffr) | | XAR | [`svxar`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svxar) | | ZIP1 (predicates) | [`svzip1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=svzip1) | | ZIP1 (vectors) | [`svzip1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int,float,bfloat]&q=svzip1) | | ZIP2 (predicates) | [`svzip2`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[bool]&q=svzip2) | | ZIP2 (vectors) | [`svzip2`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesreturnbasetype=[uint,int,float,bfloat]&q=svzip2) | #### ADDPL, ADDVL, INC and DEC The architecture provides instructions for adding or subtracting an element count, where the count might come from a pattern (such as [`svcntb_pat`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcntb_pat)) or from a predicate ([`svcntp`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcntp)). For example, INCH adds the number of halfwords in a pattern to a scalar register or to every element of a vector register. At the C and C++ level it is usually simpler to write the addition out normally. Also, having intrinsics that map directly to architectural instructions like INCH could cause confusion for pointers, since the instructions would operate on the raw integer value of the pointer. For example, applying INCH to a pointer to halfwords would effectively convert the pointer to an integer, add the number of halfwords, and then convert the result back to a pointer. The pointer would then only advance by half a vector. For these reasons there are no dedicated ACLE intrinsics for: * ADDPL and ADDVL * DECB, DECH, DECW, DECD, and DECP * INCB, INCH, INCW, INCD, and INCP Instead the implementation should use these instructions to optimize things like: ``` c svbool_t p1; ... x += svcntp_b16(p1, p1); ``` The same concerns do not apply to saturating scalar arithmetic, since using saturating arithmetic only makes sense for displacements rather than pointers. There is also no standard way of doing a saturating addition or subtraction of arbitrary integers. ACLE does therefore provide intrinsics for: * SQDECB, SQDECH, SQDECW, SQDECD, and SQDECP * SQINCB, SQINCH, SQINCW, SQINCD, and SQINCP * UQDECB, UQDECH, UQDECW, UQDECD, and UQDECP * UQINCB, UQINCH, UQINCW, UQINCD, and UQINCP #### CTERMEQ and CTERMNE CTERMEQ and CTERMNE provide a way of optimizing conditions such as: ``` c svbool_t p1, p2; uint64_t x, y; ... if (svptest_last(p1, p2) && x == y) ...stmts... ``` Here the implementation could use PTEST to test whether the last active element of `p2` is active and follow it by CTERMNE to test whether `x` is not equal to `y`. The code should then execute `stmts` if the LT condition holds (that is, if the last element is active and the “termination condition” `x != y` does not hold). There are no ACLE intrinsics that perform a combined predicate and scalar test since the separate tests should be more readable. #### MOVPRFX There are no separate ACLE intrinsics for MOVPRFX, but its use is implicit in many of the zeroing intrinsics. For example, [`svadd[_s32]_z`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svadd[_s32]_z) uses a MOVPRFX before the ADD instruction. The code generator can also use MOVPRFX to optimize calls to many `_x` and `_m` intrinsics. For example, [`svdiv[_s32]_x`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdiv[_s32]_x) can use DIV to tie the result to the first operand, DIVR to tie the result to the second operand, or a combination of MOVPRFX and DIV to store the result to a separate register. #### RDVL There is no separate ACLE intrinsic for RDVL, but the same functionality is available though the [`svcntb`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcntb), [`svcnth`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcnth), [`svcntw`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcntw), and [`svcntd`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svcntd) intrinsics. #### SVE LD1R instructions There are no separate ACLE intrinsics for LD1RB, LD1RH, LD1RW, LD1RD, LD1RSB, LD1RSH, and LD1RSW. However, the code generator can use these instructions to optimize calls to [`svdup`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svdup[_n]) in which the scalar argument comes from memory. #### SVE LDR and STR There are no separate ACLE intrinsics for SVE LDR and STR instructions, but the code generator can use these instructions to save and restore SVE registers, or to optimize calls to intrinsics like [`svld1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchieselementbitsize=[8]&q=svld1[) and [`svst1`](https://developer.arm.com/architectures/instruction-sets/intrinsics/#q=svst1[). #### SVE MOV There are no ACLE intrinsics for the unpredicated SVE MOV instructions. This is because the ACLE intrinsic calls do not imply a particular register allocation and so the code generator must decide for itself when move instructions are required. ### SVE2 BFloat16 data-processing instructions. The instructions in this section are available when __ARM_FEATURE_B16B16 is non-zero. #### BFADD, BFSUB BFloat16 floating-point add and sub (vectors) ``` c svbfloat16_t svadd[_bf16]_m (svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svadd[_bf16]_x (svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svadd[_bf16]_z (svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svadd[_n_bf16]_m (svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); svbfloat16_t svadd[_n_bf16]_x (svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); svbfloat16_t svadd[_n_bf16]_z (svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); svbfloat16_t svsub[_bf16]_m (svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svsub[_bf16]_x (svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svsub[_bf16]_z (svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svsub[_n_bf16]_m (svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); svbfloat16_t svsub[_n_bf16]_x (svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); svbfloat16_t svsub[_n_bf16]_z (svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); ``` #### BFCLAMP BFloat16 Clamp to minimum/maximum vector. ``` c svbfloat16_t svclamp[_bf16](svbfloat16_t op, svbfloat16_t min, svbfloat16_t max); ``` #### BFMAX, BFMIN BFloat16 floating-point maximum/minimum (predicated). ``` c svbfloat16_t svmax[_bf16]_m(svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svmax[_bf16]_z(svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svmax[_bf16]_x(svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svmax[_n_bf16]_m(svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); svbfloat16_t svmax[_n_bf16]_z(svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); svbfloat16_t svmax[_n_bf16]_x(svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); svbfloat16_t svmin[_bf16]_m(svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svmin[_bf16]_z(svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svmin[_bf16]_x(svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svmin[_n_bf16]_m(svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); svbfloat16_t svmin[_n_bf16]_z(svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); svbfloat16_t svmin[_n_bf16]_x(svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); ``` #### BFMAXNM, BFMINNM BFloat16 floating-point maximum/minimum number (predicated). ``` c svbfloat16_t svmaxnm[_bf16]_m(svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svmaxnm[_bf16]_z(svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svmaxnm[_bf16]_x(svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svmaxnm[_n_bf16]_m(svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); svbfloat16_t svmaxnm[_n_bf16]_z(svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); svbfloat16_t svmaxnm[_n_bf16]_x(svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); svbfloat16_t svminnm[_bf16]_m(svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svminnm[_bf16]_z(svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svminnm[_bf16]_x(svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svminnm[_n_bf16]_m(svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); svbfloat16_t svminnm[_n_bf16]_z(svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); svbfloat16_t svminnm[_n_bf16]_x(svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); ``` #### BFMLA, BFMLS BFloat16 floating-point fused multiply add or sub vectors. ``` c svbfloat16_t svmla[_bf16]_m(svbool_t pg, svbfloat16_t zda, svbfloat16_t zn, svbfloat16_t zm); svbfloat16_t svmla[_bf16]_z(svbool_t pg, svbfloat16_t zda, svbfloat16_t zn, svbfloat16_t zm); svbfloat16_t svmla[_bf16]_x(svbool_t pg, svbfloat16_t zda, svbfloat16_t zn, svbfloat16_t zm); svbfloat16_t svmla[_n_bf16]_m(svbool_t pg, svbfloat16_t zda, svbfloat16_t zn, bfloat16_t zm); svbfloat16_t svmla[_n_bf16]_z(svbool_t pg, svbfloat16_t zda, svbfloat16_t zn, bfloat16_t zm); svbfloat16_t svmla[_n_bf16]_x(svbool_t pg, svbfloat16_t zda, svbfloat16_t zn, bfloat16_t zm); svbfloat16_t svmla_lane[_bf16](svbfloat16_t zda, svbfloat16_t zn, svbfloat16_t zm, uint64_t imm_idx); svbfloat16_t svmls[_bf16]_m(svbool_t pg, svbfloat16_t zda, svbfloat16_t zn, svbfloat16_t zm); svbfloat16_t svmls[_bf16]_z(svbool_t pg, svbfloat16_t zda, svbfloat16_t zn, svbfloat16_t zm); svbfloat16_t svmls[_bf16]_x(svbool_t pg, svbfloat16_t zda, svbfloat16_t zn, svbfloat16_t zm); svbfloat16_t svmls[_n_bf16]_m(svbool_t pg, svbfloat16_t zda, svbfloat16_t zn, bfloat16_t zm); svbfloat16_t svmls[_n_bf16]_z(svbool_t pg, svbfloat16_t zda, svbfloat16_t zn, bfloat16_t zm); svbfloat16_t svmls[_n_bf16]_x(svbool_t pg, svbfloat16_t zda, svbfloat16_t zn, bfloat16_t zm); svbfloat16_t svmls_lane[_bf16](svbfloat16_t zda, svbfloat16_t zn, svbfloat16_t zm, uint64_t imm_idx); ``` #### BFMUL BFloat16 floating-point multiply vectors. ``` c svbfloat16_t svmul[_bf16]_m(svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svmul[_bf16]_x(svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svmul[_bf16]_z(svbool_t pg, svbfloat16_t zdn, svbfloat16_t zm); svbfloat16_t svmul[_n_bf16]_m(svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); svbfloat16_t svmul[_n_bf16]_x(svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); svbfloat16_t svmul[_n_bf16]_z(svbool_t pg, svbfloat16_t zdn, bfloat16_t zm); svbfloat16_t svmul_lane[_bf16](svbfloat16_t zn, svbfloat16_t zm, uint64_t imm_idx); ``` ### SVE2.1 instruction intrinsics The functions in this section are defined by the header file [``](#arm_sve.h) when `__ARM_FEATURE_SVE2p1` is defined. Some instructions overlap with the SME and SME2 architecture extensions and are additionally available in Streaming SVE mode when __ARM_FEATURE_SME is non-zero or __ARM_FEATURE_SME2 are non-zero. For convenience, the intrinsics for these instructions are listed in the following section. #### Multi-vector predicates When `__ARM_FEATURE_SVE2p1` is defined, [``](#arm_sve.h) defines the tuple types `svboolx2_t` and `svboolx4_t`. These are opaque tuple types that can be accessed using the SVE intrinsics `svsetN`, `svgetN` and `svcreateN`. `svundef2` and `svundef4` are also extended to work with `svboolx2_t` and `svboolx4_t`. e.g. ``` c svbool_t svget2[_b](svboolx2_t tuple, uint64_t imm_index); svboolx2_t svset2[_b](svboolx2_t tuple, uint64_t imm_index, svbool_t x); svboolx2_t svcreate2[_b](svbool_t x, svbool_t y); svboolx2_t svundef2_b(); ``` #### ADDQV, FADDQV Unsigned/FP add reduction of quadword vector segments. ``` c // Variants are also available for: // _s8, _s16, _u16, _s32, _u32, _s64, _u64, // _f16, _f32, _f64 uint8x16_t svaddqv[_u8](svbool_t pg, svuint8_t zn); ``` #### ANDQV, EORQV, ORQV Reduction of quadword vector segments. ``` c // Variants are also available for: // _s8, _u16, _s16, _u32, _s32, _u64, _s64 uint8x16_t svandqv[_u8](svbool_t pg, svuint8_t zn); uint8x16_t sveorqv[_u8](svbool_t pg, svuint8_t zn); uint8x16_t svorqv[_u8](svbool_t pg, svuint8_t zn); ``` #### DUPQ Broadcast indexed element within each quadword vector segment. ``` c // Variants are also available for: // _s8, _u16, _s16, _u32, _s32, _u64, _s64 // _bf16, _f16, _f32, _f64 svuint8_t svdup_laneq[_u8](svuint8_t zn, uint64_t imm_idx); ``` #### EXTQ Extract vector segment from each pair of quadword segments. ``` c // Variants are also available for: // _s8, _s16, _u16, _s32, _u32, _s64, _u64 // _bf16, _f16, _f32, _f64 svuint8_t svextq[_u8](svuint8_t zdn, svuint8_t zm, uint64_t imm); ``` #### LD1D, LD1W Contiguous zero-extending load to quadword (single vector). ``` c // Variants are also available for: // _u32, _s32 svfloat32_t svld1uwq[_f32](svbool_t, const float32_t *ptr); svfloat32_t svld1uwq_vnum[_f32](svbool_t, const float32_t *ptr, int64_t vnum); // Variants are also available for: // _u64, _s64 svfloat64_t svld1udq[_f64](svbool_t, const float64_t *ptr); svfloat64_t svld1udq_vnum[_f64](svbool_t, const float64_t *ptr, int64_t vnum); ``` #### LD1Q Gather Load Quadword. ``` c // Variants are also available for: // _u8, _u16, _s16, _u32, _s32, _u64, _s64 // _bf16, _f16, _f32, _f64 svint8_t svld1q_gather[_u64base]_s8(svbool_t pg, svuint64_t zn); svint8_t svld1q_gather[_u64base]_offset_s8(svbool_t pg, svuint64_t zn, int64_t offset); svint8_t svld1q_gather_[u64]offset[_s8](svbool_t pg, const int8_t *base, svuint64_t offset); // Variants are also available for: // _u16, _u32, _s32, _u64, _s64 // _bf16, _f16, _f32, _f64 svint16_t svld1q_gather_[u64]index[_s16](svbool_t pg, const int16_t *base, svuint64_t index); svint8_t svld1q_gather[_u64base]_index_s8(svbool_t pg, svuint64_t zn, int64_t index); ``` #### LD2Q, LD3Q, LD4Q Contiguous load two, three or four quadword structures. ``` c // Variants are also available for: // _u8, _u16, _s16, _u32, _s32, _u64, _s64 // _bf16, _f16, _f32, _f64 svint8x2_t svld2q[_s8](svbool_t pg, const int8_t *rn); svint8x2_t svld2q_vnum[_s8](svbool_t pg, const int8_t *rn, uint64_t vnum); svint8x3_t svld3q[_s8](svbool_t pg, const int8_t *rn); svint8x3_t svld3q_vnum[_s8](svbool_t pg, const int8_t *rn, uint64_t vnum); svint8x4_t svld4q[_s8](svbool_t pg, const int8_t *rn); svint8x4_t svld4q_vnum[_s8](svbool_t pg, const int8_t *rn, uint64_t vnum); ``` #### UMAXQV, SMAXQV, FMAXQV, UMINQV, SMINQV, FMINQV Max/Min reduction of quadword vector segments. ``` c // Variants are also available for: // _s8, _u16, _s16, _u32, _s32, _u64, _s64 // _f16, _f32, _f64 uint8x16_t svmaxqv[_u8](svbool_t pg, svuint8_t zn); uint8x16_t svminqv[_u8](svbool_t pg, svuint8_t zn); ``` #### FMAXNMQV, FMINNMQV Max/Min recursive reduction of quadword vector segments. ``` c // Variants are also available for _f32, _f64 float16x8_t svmaxnmqv[_f16](svbool_t pg, svfloat16_t zn); float16x8_t svminnmqv[_f16](svbool_t pg, svfloat16_t zn); ``` #### PMOV ``` c // Variants are available for: // _s8, _u16, _s16, _s32, _u32, _s64, _u64 svbool_t svpmov_lane[_u8](svuint8_t zn, uint64_t imm); // Variants are available for: // _s8, _s16, _u16, _s32, _u32, _s64, _u64 svbool_t svpmov[_u8](svuint8_t zn); // Variants are available for: // _s16, _s32, _u32, _s64, _u64 svuint16_t svpmov_lane[_u16]_m(svuint16_t zd, svbool_t pn, uint64_t imm); // Variants are also available for: // _s8, _u16, _s16, _u32, _s32, _u64, _s64 svuint8_t svpmov_u8_z(svbool_t pn); ``` #### ST1D, ST1W Contiguous store of single vector operand, truncating from quadword. ``` c // Variants are also available for: // _u32, _s32 void svst1wq[_f32](svbool_t, const float32_t *ptr, svfloat32_t data); void svst1wq_vnum[_f32](svbool_t, const float32_t *ptr, int64_t vnum, svfloat32_t data); // Variants are also available for: // _u64, _s64 void svst1dq[_f64](svbool_t, const float64_t *ptr, svfloat64_t data); void svst1dq_vnum[_f64](svbool_t, const float64_t *ptr, int64_t vnum, svfloat64_t data); ``` #### ST1Q Scatter store quadwords. ``` c // Variants are also available for: // _u8, _u16, _s16, _u32, _s32, _u64, _s64 // _bf16, _f16, _f32, _f64 void svst1q_scatter[_u64base][_s8](svbool_t pg, svuint64_t zn, svint8_t data); void svst1q_scatter[_u64base]_offset[_s8](svbool_t pg, svuint64_t zn, int64_t offset, svint8_t data); void svst1q_scatter_[u64]offset[_s8](svbool_t pg, const uint8_t *base, svuint64_t offset, svint8_t data); // Variants are also available for: // _u16, _u32, _s32, _u64, _s64 // _bf16, _f16, _f32, _f64 void svst1q_scatter[_u64base]_index[_s8](svbool_t pg, svuint64_t zn, int64_t index, svint8_t data); void svst1q_scatter_[u64]index_[s16](svbool_t pg, const int16_t *base, svuint64_t index, svint16_t data); ``` #### ST2Q, ST3Q, ST4Q Contiguous store. ``` c // Variants are also available for: // _s8 _u16, _s16, _u32, _s32, _u64, _s64 // _bf16, _f16, _f32, _f64 void svst2q[_u8](svbool_t pg, uint8_t *rn, svuint8x2_t zt); void svst2q_vnum[_u8](svbool_t pg, uint8_t *rn, int64_t vnum, svuint8x2_t zt); void svst3q[_u8](svbool_t pg, uint8_t *rn, svuint8x3_t zt); void svst3q_vnum[_u8](svbool_t pg, uint8_t *rn, int64_t vnum, svuint8x3_t zt); void svst4q[_u8](svbool_t pg, uint8_t *rn, svuint8x4_t zt); void svst4q_vnum[_u8](svbool_t pg, uint8_t *rn, int64_t vnum, svuint8x4_t zt); ``` #### TBLQ Programmable table lookup within each quadword vector segment (zeroing). ``` c // Variants are also available for: // _u8, _u16, _s16, _u32, _s32, _u64, _s64 // _bf16, _f16, _f32, _f64 svint8_t svtblq[_s8](svint8_t zn, svuint8_t zm); ``` #### TBXQ Programmable table lookup within each quadword vector segment (merging). ``` c // Variants are also available for: // _u8, _u16, _s16, _u32, _s32, _u64, _s64 // _bf16, _f16, _f32, _f64 svint8_t svtbxq[_s8](svint8_t fallback, svint8_t zn, svuint8_t zm); ``` #### UZPQ1, UZPQ2 Concatenate elements within each pair of quadword vector segments. ``` c // Variants are also available for: // _s8, _u16, _s16, _u32, _s32, _u64, _s64 // _bf16, _f16, _f32, _f64 svuint8_t svuzpq1[_u8](svuint8_t zn, svuint8_t zm); svuint8_t svuzpq2[_u8](svuint8_t zn, svuint8_t zm); ``` #### ZIPQ1, ZIPQ2 Interleave elements from halves of each pair of quadword vector segments. ``` c // Variants are also available for: // _s8, _u16, _s16, _u32, _s32, _u64, _s64 // _bf16, _f16, _f32, _f64 svuint8_t svzipq1[_u8](svuint8_t zn, svuint8_t zm); svuint8_t svzipq2[_u8](svuint8_t zn, svuint8_t zm); ``` # SME language extensions and intrinsics The specification for SME is in [**Beta** state](#current-status-and-anticipated-changes) and may change or be extended in the future. ## Controlling the use of streaming mode ### Introduction to streaming and non-streaming mode The AArch64 architecture defines a concept called “streaming mode”, controlled by a processor state bit called PSTATE.SM. At any given point in time, the processor is either in streaming mode (PSTATE.SM==1) or in non-streaming mode (PSTATE.SM==0). There is an instruction called SMSTART to enter streaming mode and an instruction called SMSTOP to return to non-streaming mode. Streaming mode has three main effects on C and C++ code: * It can change the length of SVE vectors and predicates: the length of an SVE vector in streaming mode is called the “streaming vector length” (SVL), which might be different from the normal non-streaming vector length. See [Effect of streaming mode on VL](#effect-of-streaming-mode-on-vl) for more details. * Some instructions can only be executed in streaming mode, which means that their associated ACLE intrinsics can only be used in streaming mode. These intrinsics are called “streaming intrinsics”. * Some other instructions can only be executed in non-streaming mode, which means that their associated ACLE intrinsics can only be used in non-streaming mode. These intrinsics are called “non-streaming intrinsics”. The C and C++ standards define the behavior of programs in terms of an “abstract machine”. As an extension, the ACLE specification applies the distinction between streaming mode and non-streaming mode to this abstract machine: at any given point in time, the abstract machine is either in streaming mode or in non-streaming mode. This distinction between processor mode and abstract machine mode is mostly just a dry specification detail. However, the usual “as if” rule applies: the processor's actual mode at runtime can be different from the abstract machine's mode, provided that this does not alter the behavior of the program. One practical consequence of this is that C and C++ code does not specify the exact placement of SMSTART and SMSTOP instructions; the source code simply places limits on where such instructions go. For example, when stepping through a program in a debugger, the processor mode might sometimes be different from the one implied by the source code. ACLE provides attributes that specify whether the abstract machine executes statements: * in non-streaming mode, in which case they are called “non-streaming statements” * in streaming mode, in which case they are called “streaming statements” * in either mode, in which case they are called “streaming-compatible statements” At present, the classification can only be controlled at function granularity: the statements in a function are all non-streaming, all streaming, or all streaming-compatible. When no attribute specifies otherwise, all statements in a function are non-streaming. As noted above, this classification affects which intrinsics the statements can use. It also affects the length of SVE vectors and predicates. A program is [ill-formed](#ill-formed) if: * a [streaming statement](#streaming-statement) or a [streaming-compatible statement](#streaming-compatible-statement) contains an [evaluated call](#evaluated-call) to a [non-streaming intrinsic](#non-streaming-intrinsic). * a [non-streaming statement](#non-streaming-statement) or a [streaming-compatible statement](#streaming-compatible-statement) contains an [evaluated call](#evaluated-call) to a [streaming intrinsic](#streaming-intrinsic). The current mode of the abstract machine can be queried using [`__arm_in_streaming_mode`](#arm_in_streaming_mode). ### Changing streaming mode locally Adding an [`__arm_locally_streaming`](#arm_locally_streaming) [keyword attribute](#keyword-attributes) to a function specifies that all the statements in the function are [streaming statements](#streaming-statement). The program automatically puts the [abstract machine](#abstract-machine) into streaming mode before executing the statements and automatically restores the previous mode afterwards. This choice is internal to the function definition. It is not visible to callers and so it can be changed without affecting the function's binary interface. (In other words, it can be changed without requiring all callers to be recompiled.) For example: ``` c int nonstreaming_fn(void) { return __arm_in_streaming_mode(); // Returns 0 } __arm_locally_streaming int streaming_fn(void) { // Function automatically switches into streaming mode on entry svsetffr(); // Ill-formed, calls a non-streaming intrinsic return __arm_in_streaming_mode(); // Returns 1 } // Function automatically switches out of streaming mode on return int (*ptr1)(void) = nonstreaming_fn; // OK int (*ptr2)(void) = streaming_fn; // OK ``` This approach can be useful when implementing existing APIs, including when overriding virtual functions. It allows the use of SME to be an internal implementation detail. The [`__arm_locally_streaming`](#arm_locally_streaming) [keyword attribute](#keyword-attributes) is an optional feature; it is only guaranteed to be present if the implementation predefines the `__ARM_FEATURE_LOCALLY_STREAMING` macro to a nonzero value. ### Managing streaming mode across function boundaries In addition to [changing streaming mode locally](#changing-streaming-mode-locally), ACLE provides [keyword attributes](#keyword-attributes) for managing streaming mode across function boundaries. This can be useful in the following example situations: * An SME operation is split across several cooperating subroutines (as is often the case). The SME operation as a whole is designed to execute exclusively in streaming mode, so mid-operation mode switches should be avoided for performance reasons. * A function provides a public API that is specific to SME. Again, callers to such functions would want to avoid the overhead of switching modes at function call boundaries. * Some functions are compatible with both streaming and non-streaming mode. Marking them as “streaming-compatible” allows them to be called in either mode, without changing the vector length. For example, this could be useful for “length agnostic” SVE math routines. For this reason, the “streaming”, “non-streaming” and “streaming-compatible” classification extends to function types: * By default, function types are “non-streaming types”. * Attaching an [`__arm_streaming`](#arm_streaming) [keyword attribute](#keyword-attributes) to a function type makes it a “streaming type”. * Attaching an [`__arm_streaming_compatible`](#arm_streaming_compatible) [keyword attribute](#keyword-attributes) to a function type makes it a “streaming-compatible type”. The function type classification decides which mode the [abstract machine](#abstract-machine) is in on entry to the function and which mode the abstract machine is in on return from the function. The program automatically switches mode as necessary before calling a function and restores the previous mode on return; see [Changes in streaming mode](#changes-in-streaming-mode) for details. If the function forms part of the object code's ABI, the function type classification also determines whether the function has a “non-streaming interface”, a “streaming interface” or a “streaming-compatible interface”; see [[AAPCS64]](#AAPCS64) for details. By default, the classification of a function type carries over to the classification of the statements in the function's definition, if any. However, this can be overridden by the [`__arm_locally_streaming`](#arm_locally_streaming) [keyword attribute](#keyword-attributes); see [Changing streaming mode locally](#changing-streaming-mode-locally) for details. For example: ``` c // "n" stands for "non-streaming" // "s" stands for "streaming" // "sc" stands for "streaming-compatible" void n_callee(void); void s_callee(void) __arm_streaming; void sc_callee(void) __arm_streaming_compatible; void (*n_callback)(void); void (*s_callback)(void) __arm_streaming; void (*sc_callback)(void) __arm_streaming_compatible; int n_caller(void) { n_callee(); // No mode switch (*n_callback)(); // No mode switch s_caller(); // Temporarily switches to streaming mode (*s_callback)(); // Temporarily switches to streaming mode sc_caller(); // No mode switch (*sc_callback)(); // No mode switch return __arm_in_streaming_mode(); // Returns 0 } int s_caller(void) __arm_streaming { n_callee(); // Temporarily switches to non-streaming mode (*n_callback)(); // Temporarily switches to non-streaming mode s_caller(); // No mode switch (*s_callback)(); // No mode switch sc_caller(); // No mode switch (*sc_callback)(); // No mode switch return __arm_in_streaming_mode(); // Returns 1 } int sc_caller(void) __arm_streaming_compatible { n_callee(); // Temporarily switches to non-streaming mode (*n_callback)(); // Temporarily switches to non-streaming mode s_caller(); // Temporarily switches to streaming mode (*s_callback)(); // Temporarily switches to streaming mode sc_caller(); // No mode switch (*sc_callback)(); // No mode switch return __arm_in_streaming_mode(); // Might return 0 or 1 } ``` A function type in one category is incompatible with a function type in another category, even if the types are otherwise identical. For example: ``` c // "n" stands for "non-streaming" // "s" stands for "streaming" // "sc" stands for "streaming-compatible" void n_callee(void); void s_callee(void) __arm_streaming; void sc_callee(void) __arm_streaming_compatible; void (*n_callback)(void); void (*s_callback)(void) __arm_streaming; void (*sc_callback)(void) __arm_streaming_compatible; void code() { n_callback = n_callee; // OK n_callback = s_callee; // Ill-formed n_callback = sc_callee; // Ill-formed s_callback = n_callee; // Ill-formed s_callback = s_callee; // OK s_callback = sc_callee; // Ill-formed sc_callback = n_callee; // Ill-formed sc_callback = s_callee; // Ill-formed sc_callback = sc_callee; // OK } ``` A type that has both an [`__arm_streaming`](#arm_streaming) [keyword attribute](#keyword-attributes) and an [`__arm_streaming_compatible`](#arm_streaming_compatible) [keyword attribute](#keyword-attributes) is [ill-formed](#ill-formed). ### Effect of streaming mode on VL The value returned by an SVE intrinsic like `svcntb` depends on whether or not the [abstract machine](#abstract-machine) is in streaming mode: if the abstract machine is in streaming mode then the returned value depends on the “streaming vector length” (SVL), otherwise the returned value depends on the non-streaming vector length. The runtime size of SVE vector and predicate types varies in the same way. For example, an `svint8_t` object created while the abstract machine is in streaming mode will have SVL bits, whereas an `svint8_t` object created while the abstract machine is in non-streaming mode will have the size specified by the non-streaming vector length. The following definitions are useful when describing the consequences of this behavior on the vector length: * A type T is said to be “VL-dependent” if an object of type T created while the [abstract machine](#abstract-machine) is in streaming mode has a different size from an object of type T created while the abstract machine is in non-streaming mode. Pointer and reference types are never VL-dependent. No types are VL-dependent if the streaming and non-streaming vector lengths are equal. * As a shorthand, an object or value is said to be VL-dependent if its type is VL-dependent. Like normal objects, a VL-dependent object never changes size after it has been created. The “VL-dependent” classification instead decides when it is valid to access the object, as described below. * A VL-dependent object created while the abstract machine is in streaming mode is called a “streaming object”. * A VL-dependent object created while the abstract machine is in non-streaming mode is called a “non-streaming object”. If any of the following events occurs during the execution of a program, then the behavior is undefined: * The program accesses a [non-streaming object](#non-streaming-object) while the [abstract machine](#abstract-machine) is in streaming mode. * The program accesses a [streaming object](#streaming-object) while the [abstract machine](#abstract-machine) is in non-streaming mode. ### Streaming callers and streaming callees If, during the execution of a program, a function F1 calls a function F2, then: * F1 is said to be a “streaming caller” if: * F1's statements are [streaming statements](#streaming-statement); or * F1's statements are [streaming-compatible statements](#streaming-compatible-statement) and F1's caller is itself a streaming caller. Otherwise, F1 is said to be a “non-streaming caller”. * F2 is said to be a “streaming callee” if: * F2 has a [streaming type](#streaming-type); or * F2 has a [streaming-compatible type](#streaming-compatible-type) and F1 is a streaming caller. Otherwise, F2 is said to be a “non-streaming callee”. See [Calling restrictions related to streaming mode](#calling-restrictions-related-to-streaming-mode) for some examples. ### Changes in streaming mode Calls from a [non-streaming caller](#non-streaming-caller) to a [streaming callee](#streaming-callee) involve a temporary change into streaming mode. The [abstract machine](#abstract-machine) enters streaming mode for the duration of the call and returns to non-streaming mode afterwards. Similarly, calls from a [streaming caller](#streaming-caller) to a [non-streaming callee](#non-streaming-callee) involve a temporary change out of streaming mode. The [abstract machine](#abstract-machine) leaves streaming mode for the duration of the call and reenters streaming mode afterwards. In both cases, these changes of mode are automatic and it is the compiler's responsibility to insert the necessary instructions. There are no intrinsics that map directly to SMSTART and SMSTOP. Semantically, the sequencing of such calls is as follows: 1. Evaluate the function arguments according to the normal C/C++ rules and create any temporary objects necessary for performing the call. 2. Switch the abstract machine to the callee's mode. 3. Call the callee function. 4. Switch the abstract machine back to the original mode. 5. Process the value returned by the call (if any). The intention is that the change in mode binds as closely to the call as possible. ### Calling restrictions related to streaming mode If any of the following events occurs during the execution of a program, then the behavior is undefined: * a [streaming caller](#streaming-caller) passes a [VL-dependent](#vl-dependent) argument to a [non-streaming callee](#non-streaming-callee) * a [non-streaming caller](#non-streaming-caller) passes a [VL-dependent](#vl-dependent) argument to a [streaming callee](#streaming-callee) * a [non-streaming callee](#non-streaming-callee) receives a [VL-dependent](#vl-dependent) argument and the callee has an [`__arm_locally_streaming`](#arm_locally_streaming) [keyword attribute](#keyword-attributes) * a [streaming callee](#streaming-callee) returns a [VL-dependent](#vl-dependent) value to a [non-streaming caller](#non-streaming-caller) * a [non-streaming callee](#non-streaming-callee) returns a [VL-dependent](#vl-dependent) value to a [streaming caller](#streaming-caller) * a [non-streaming callee](#non-streaming-callee) returns a [VL-dependent](#vl-dependent) value and the callee has an [`__arm_locally_streaming`](#arm_locally_streaming) [keyword attribute](#keyword-attributes) The following code gives some examples. In each case, the assumption is that the non-streaming vector length is different from the streaming vector length: ``` c // "n" stands for "non-streaming" // "s" stands for "streaming" // "sc" stands for "streaming-compatible" // "ls" stands for "locally streaming" void n_callee(svint8_t); void s_callee(svbool_t) __arm_streaming; void sc_callee(svint8_t) __arm_streaming_compatible; __arm_locally_streaming void ls_callee(svbool_t pg) { // Invokes undefined behavior if called. } void n_caller(void) { svint8_t i = ...; svbool_t b = ...; n_callee(i); // OK: non-streaming callee s_callee(b); // Undefined behavior: streaming callee sc_callee(i); // OK: non-streaming callee ls_callee(b); // call is OK: non-streaming callee. However, // as noted above, the callee invokes undefined // behavior internally } void s_caller(void) __arm_streaming { svint8_t i = ...; svbool_t b = ...; n_callee(i); // Undefined behavior: non-streaming callee s_callee(b); // OK: streaming callee sc_callee(i); // OK: streaming callee ls_callee(b); // Undefined behavior: non-streaming callee } void sc_caller(void) __arm_streaming_compatible { svint8_t i = ...; svbool_t b = ...; n_callee(i); // Undefined behavior if sc_caller was called // in streaming mode (but not otherwise) s_callee(b); // Undefined behavior if sc_caller was called // in non-streaming mode (but not otherwise) sc_callee(i); // OK: keeps current streaming/non-streaming mode ls_callee(b); // Undefined behavior if sc_caller was called // in streaming mode, but the call itself is // OK otherwise. As noted above, the callee // invokes undefined behavior internally } ``` If the streaming and non-streaming vector lengths are equal then there is no undefined behavior in the code above. ### `asm` restrictions related to streaming mode Some ACLE implementations might support the GNU “inline asm” extension. If so, the value of PSTATE.SM at the start of such inline asms is guaranteed to match the mode of the [abstract machine](#abstract-machine). For example, PSTATE.SM is guaranteed to be 1 at the start of inline asms in [streaming statements](#streaming-statement) and 0 at the start of inline asms in [non-streaming statements](#non-streaming-statement). All inline asms must preserve the value of PSTATE.SM. Therefore: * An asm entered in streaming mode must finish in streaming mode. * An asm entered in non-streaming mode must finish in non-streaming mode. The behavior in other cases is undefined. An inline asm can temporarily switch mode internally, such as using an SMSTART/SMSTOP pair. However, such mode switches invalidate all Z and P register state. The asm's “clobber list” must mention any registers whose values might be changed by the asm. ## ZA storage SME provides an area of storage called ZA, of size SVL.B×SVL.B bytes. It also provides a processor state bit called PSTATE.ZA to control whether ZA is enabled. In C and C++ code, access to ZA is controlled at function granularity: a function either [uses](#uses-state) ZA or it does not. Another way to say this is that a function either “has ZA state” or it does not. If a function does have ZA state, the function can either [share](#shares-state) that ZA state with the function's caller or create new ZA state “from scratch”. In the latter case, it is the compiler's responsibility to free up ZA so that the function can use it; see the description of the lazy saving scheme in [[AAPCS64]](#AAPCS64) for details about how the compiler does this. These possibilities give a one-out-of-three choice for how a function handles ZA: 1. The function has no [ZA state](#za-state). This is the default. 2. The function has [ZA state](#za-state) that it shares with its caller. This is indicated by adding a [state-sharing attribute](#ways-of-sharing-state) to the function type, such as `__arm_inout("za")`. 3. The function has [ZA state](#za-state) that it creates “from scratch” and that it does not share with its caller. This is indicated by adding [`__arm_new("za")`](#arm_new) to the function definition. Functions that have ZA state can use the [SME instruction intrinsics](#sme-instruction-intrinsics) to manipulate that state. ## ZT0 Lookup Table When ZA storage is enabled, SME2 additionally provides access to a 64-byte large lookup table called ZT0 which can be accessed through specialized instructions. ZT0 is architecturally linked to ZA such that changing PSTATE.ZA enables or disables both ZA and ZT0 simultaneously. This means that when the hardware supports SME2, a function that has [ZA state](#za-state) also has ZT state. ## SME keyword attributes ACLE adds several SME-related keyword attributes. See [Keyword attributes](#keyword-attributes) for general remarks about these keywords. Except where noted otherwise, function types that have an attribute are incompatible with function types that do not. For example: ``` c // "n" stands for "non-streaming" // "s" stands for "streaming" typedef void (*n_callback_type)(void); n_callback_type n_callback_ptr; void n_extern_function(void); void n_local_function(void) { ... } typedef void (*s_callback_type)(void) __arm_streaming; s_callback_type s_callback_ptr; void s_extern_function(void) __arm_streaming; void s_local_function(void) __arm_streaming { ... } void foo() { n_callback_ptr = n_callback_ptr; // OK n_callback_ptr = n_extern_function; // OK n_callback_ptr = n_local_function; // OK n_callback_ptr = s_callback_ptr; // Ill-formed n_callback_ptr = s_extern_function; // Ill-formed n_callback_ptr = s_local_function; // Ill-formed s_callback_ptr = n_callback_ptr; // Ill-formed s_callback_ptr = n_extern_function; // Ill-formed s_callback_ptr = n_local_function; // Ill-formed s_callback_ptr = s_callback_ptr; // OK s_callback_ptr = s_extern_function; // OK s_callback_ptr = s_local_function; // OK } ``` The function type attributes cannot be used with K&R-style [unprototyped function](#unprototyped-function) types. For example: ``` c #define ATTR __arm_streaming typedef int ft1() ATTR; // Ill-formed in C, C18 and earlier, OK in // later versions of C and in C++ int f1() ATTR { ... } // Likewise typedef int ft2(void) ATTR; // OK int f2(void) ATTR { ... } // OK ``` ### SME keyword attributes related to streaming mode #### `__arm_streaming` This [keyword attribute](#keyword-attributes) applies to **function types** and specifies the following: * If the function is defined, all statements in that definition are [streaming statements](#streaming-statement). * The program switches the [abstract machine](#abstract-machine) into streaming mode before calling the function and restores the previous mode after the function has returned. * If the function forms part of the object code's ABI, that object code function has a “streaming interface”; see [[AAPCS64]](#AAPCS64) for more details. Using this attribute does not place any restriction on the function's argument and return types. For example, an `__arm_streaming` function can take arguments of type `int32x4_t` even though that type is generally associated with non-streaming Advanced SIMD code. See [Managing streaming mode across function boundaries](#managing-streaming-mode-across-function-boundaries) for more information. #### `__arm_streaming_compatible` This [keyword attribute](#keyword-attributes) applies to **function types** and specifies the following: * If the function is defined, all statements in that definition are by default [streaming-compatible statements](#streaming-compatible-statement). This can be overridden by the [`__arm_locally_streaming`](#arm_locally_streaming) keyword attribute. * The [abstract machine](#abstract-machine) does not change into or out of streaming mode before calling the function and does not (need to) restore the previous mode after the function has returned. * If the function forms part of the object code's ABI, that object code function has a “streaming-compatible interface”; see [[AAPCS64]](#AAPCS64) for more details. Using this attribute does not place any restriction on the function's argument and return types. For example, an `__arm_streaming_compatible` function can take arguments of type `int32x4_t` even though that type is generally associated only with non-streaming Advanced SIMD code. See [Managing streaming mode across function boundaries](#managing-streaming-mode-across-function-boundaries) for more information. #### `__arm_locally_streaming` This [keyword attribute](#keyword-attributes) is only guaranteed to be supported by ACLE implementations that predefine the macro `__ARM_FEATURE_LOCALLY_STREAMING` to a nonzero value. The attribute applies to **function definitions** and specifies that all statements in the function definition are [streaming statements](#streaming-statement). The attribute is redundant (but still valid) for functions that have an [`__arm_streaming`](#arm_streaming) type. See [Changing streaming mode locally](#changing-streaming-mode-locally) for more information. ## SME types ### Predicate-as-counter SME2 adds a new kind of predicate, named *predicate-as-counter* which is used for multi-vector predication. It describes a predicate mask that can span multiple predicate registers with `K` `true` values followed by all `false` values, or `K` `false` values followed by all `true` values, for a given element type. When `__ARM_FEATURE_SME2` is defined, [``](#arm_sme.h) defines a single sizeless predicate-as-counter type named `svcount_t`. `svcount_t` and `svbool_t` are both used to represent predicate masks, but they cannot be used interchangeably. The ACLE allows these types to be casted from one to another using the `svcount_t svreinterpret_c(svbool_t)` and `svbool_t svreinterpret_b(svcount_t)` intrinsics, although the reinterpreted values may not be sensible in the other format. To safely extract a sensible mask from a `svcount_t`, the `svpext` functions should be used. ### Multi-vector predicates When `__ARM_FEATURE_SME2` is defined, [``](#arm_sme.h) defines the tuple types `svboolx2_t` and `svboolx4_t`. These are opaque tuple types that can be accessed using the SVE intrinsics `svsetN`, `svgetN` and `svcreateN`. `svundef2` and `svundef4` are also extended to work with `svboolx2_t` and `svboolx4_t`. For example: ``` c svbool_t svget2[_b](svboolx2_t tuple, uint64_t imm_index); svboolx2_t svset2[_b](svboolx2_t tuple, uint64_t imm_index, svbool_t x); svboolx2_t svcreate2[_b](svbool_t x, svbool_t y); svboolx2_t svundef2_b(); ``` ## SME functions and intrinsics [``](#arm_sme.h) declares various support functions and defines various intrinsics. The support functions have [external linkage](#external-linkage), like standard C functions such as `memcpy` do. However, as noted in [Intrinsics](#intrinsics), it is unspecified whether the intrinsics are functions and, if so, what linkage they have. There are many more intrinsics than support functions, so everything described in this section is an intrinsic unless its individual description says otherwise. If an intrinsic is implemented as a macro rather than a function, the macro must behave “as if” it had the prototype and attributes specified in this section. ### SME PSTATE functions #### Prototypes ``` c bool __arm_has_sme(void) __arm_streaming_compatible; bool __arm_in_streaming_mode(void) __arm_streaming_compatible; // Function with external linkage. void __arm_za_disable(void) __arm_streaming_compatible; ``` #### Semantics **`__arm_has_sme()`** > This call returns true if the current thread “has access to SME”; > see [[AAPCS64]](#AAPCS64) for a more detailed definition of this term. > > One way of implementing this function is to call `__arm_sme_state` > and then return the top bit of X0. See [[AAPCS64]](#AAPCS64) for > more details about `__arm_sme_state`. **`__arm_in_streaming_mode()`** > This call returns true if the [abstract machine](#abstract-machine) is > in streaming mode. It always returns true when called from [streaming > statements](#streaming-statement) and it always return false when > called from [non-streaming statements](#non-streaming-statement). > However, the call is not semantically a constant expression even in > those cases. **`__arm_za_disable()`** > This call commits any pending lazy save and turns ZA off; > see [[AAPCS64]](#AAPCS64) for details. > > Note: since this is a [private-ZA](#private-za) function, > it is valid (though pointless) to call it from a function that has > [ZA state](#za-state). The compiler would simply reenable ZA after the > call and reload the saved ZA state. ### SME ZA state assertions #### Prototypes ``` c void svundef_za() __arm_streaming_compatible; ``` #### Semantics **`svundef_za()`** > This call asserts that ZA does not currently have any useful data. > Semantically, it fills ZA with unpredictable data, although from > a quality of implementation perspective, it should not generate > any object code. > > The call can be used as an optimization hint to the compiler, so that > the compiler does not insert unnecessary code to save and restore the > current ZA contents. The call might also be useful for static analysis. ### SME instruction intrinsics The intrinsics in this section have the following properties in common: * Every argument named `tile` or `tile_mask` must be an integer constant expression in the range of the underlying instruction. * Some SME instructions identify a slice of ZA using the sum of a 32-bit general-purpose register and an immediate offset. The intrinsics for these instructions have a 32-bit argument named `slice`, which is interpreted as follows: * If the intrinsic also has a `vnum` argument, the ZA slice number is calculated by adding `vnum` to `slice`. Both `slice` and `vnum` can be variable. * Otherwise, `slice` specifies the ZA slice number directly; that is, it represents the sum of the 32-bit register and the immediate offset. `slice` can be variable. * ZA loads and stores do not use typed pointers, since there is no C or C++ type information associated with the contents of ZA. * Intrinsics have a `_hor` suffix if they operate on horizontal slices of a given ZA tile and a `_ver` suffix if they operate on vertical slices of a given ZA tile. SME2 adds operations that work on groups of SVE vectors, ZA tile slices or ZA array vectors. The intrinsics model this in the following way: * Multi-vector operands are groups of SVE data vectors, that use the same tuple types as defined in the [SVE ACLE](#sve-vector-types), for example, `svint32x2_t` for a multi-vector operand of two 32-bit element vectors, or `svint64x4_t` for a multi-vector operand of four 64-bit element vectors. * The architecture distinguishes between multi-vector operands with consecutive registers and multi-vector operands with strided registers. This level of detail is not exposed to the C/C++ intrinsics or types. It is left up to the compiler to choose the most optimal form. * Intrinsic functions have a `_x2` or `_x4` suffix if the function\'s widest type is a vector tuple of 2 or 4 data vectors and the function operates purely on vectors, not on the matrix array or tile slices. The suffix is only present on overloaded names if it cannot be inferred from arguments. * Intrinsic functions have a `_vg2` or `_vg4` suffix if the function operates on groups of 2 or 4 ZA tile slices. For example: ``` c // Reads 2 consecutive horizontal tile slices from ZA into multi-vector. svint8x2_t svread_hor_za8_s8_vg2(uint64_t tile, uint32_t slice) __arm_streaming __arm_in("za"); ``` * Intrinsic functions have a `_vg1x2`, `_vg1x4` suffix if the function operates on 2 or 4 single-vector groups within the ZA array. * Intrinsic functions have a `_vg2x1`, `_vg2x2`, `_vg2x4` suffix if the function operates on 1, 2 or 4 double-vector groups within the ZA array. * Intrinsic functions have a `_vg4x1`, `_vg4x2`, `_vg4x4` suffix if the function operates on 1, 2 or 4 quad-vector groups within the ZA array. For example: ``` c // SMLAL intrinsic for 2 quad-vector groups. void svmla_lane_za32[_s8]_vg4x2(uint32_t slice, svint8x2_t zn, svint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); ``` * Intrinsic functions that take a multi-vector operand may have additional suffixes to distinguish them from other forms for the same intrinsic: * a `_single` suffix if they take one multi-vector operand and one (single) vector operand. * a `_lane` suffix if they take one multi-vector operand and one indexed vector operand with an immediate to specify the indexed elements. ``` c void svmla_za32[_s8]_vg4x2(uint32_t slice, svint8x2_t zn, svint8x2_t zm) __arm_streaming __arm_inout("za"); void svmla[_single]_za32[_s8]_vg4x2(uint32_t slice, svint8x2_t zn, svint8_t zm) __arm_streaming __arm_inout("za"); void svmla_lane_za32[_s8]_vg4x2(uint32_t slice, svint8x2_t zn, svint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); ``` #### LD1B, LD1H, LD1W, LD1D, LD1Q ``` c // Also for _za16, _za32, _za64 and _za128 (with the same prototype). void svld1_hor_za8(uint64_t tile, uint32_t slice, svbool_t pg, const void *ptr) __arm_streaming __arm_inout("za"); // Synthetic intrinsic: adds vnum to slice and vnum * svcntsb() to the // address given by ptr. // // Also for _za16, _za32, _za64 and _za128 (with the same prototype). void svld1_hor_vnum_za8(uint64_t tile, uint32_t slice, svbool_t pg, const void *ptr, int64_t vnum) __arm_streaming __arm_inout("za"); // Also for _za16, _za32, _za64 and _za128 (with the same prototype). void svld1_ver_za8(uint64_t tile, uint32_t slice, svbool_t pg, const void *ptr) __arm_streaming __arm_inout("za"); // Synthetic intrinsic: adds vnum to slice and vnum * svcntsb() to the // address given by ptr. // // Also for _za16, _za32, _za64 and _za128 (with the same prototype). void svld1_ver_vnum_za8(uint64_t tile, uint32_t slice, svbool_t pg, const void *ptr, int64_t vnum) __arm_streaming __arm_inout("za"); ``` #### LDR ``` c void svldr_za(uint32_t slice, const void *ptr) __arm_streaming_compatible __arm_inout("za"); // Adds vnum to slice and vnum * svcntsb() to the address given by ptr. // This can be done in a single instruction if vnum is a constant in the // range [0, 15]. The intrinsic is synthetic for other vnum parameters. void svldr_vnum_za(uint32_t slice, const void *ptr, int64_t vnum) __arm_streaming_compatible __arm_inout("za"); ``` #### ST1B, ST1H, ST1W, ST1D, ST1Q ``` c // Also for _za16, _za32, _za64 and _za128 (with the same prototype). void svst1_hor_za8(uint64_t tile, uint32_t slice, svbool_t pg, void *ptr) __arm_streaming __arm_in("za"); // Synthetic intrinsic: adds vnum to slice and vnum * svcntsb() to the // address given by ptr. // // Also for _za16, _za32, _za64 and _za128 (with the same prototype). void svst1_hor_vnum_za8(uint64_t tile, uint32_t slice, svbool_t pg, void *ptr, int64_t vnum) __arm_streaming __arm_in("za"); // Also for _za16, _za32, _za64 and _za128 (with the same prototype). void svst1_ver_za8(uint64_t tile, uint32_t slice, svbool_t pg, void *ptr) __arm_streaming __arm_in("za"); // Synthetic intrinsic: adds vnum to slice and vnum * svcntsb() to the // address given by ptr. // // Also for _za16, _za32, _za64 and _za128 (with the same prototype). void svst1_ver_vnum_za8(uint64_t tile, uint32_t slice, svbool_t pg, void *ptr, int64_t vnum) __arm_streaming __arm_in("za"); ``` #### STR ``` c void svstr_za(uint32_t slice, void *ptr) __arm_streaming_compatible __arm_in("za"); // Adds vnum to slice and vnum * svcntsb() to the address given by ptr. // This can be done in a single instruction if vnum is a constant in the // range [0, 15]. The intrinsic is synthetic for other vnum parameters. void svstr_vnum_za(uint32_t slice, void *ptr, int64_t vnum) __arm_streaming_compatible __arm_in("za"); ``` #### MOVA The intrinsics below read horizontal ZA slices. In each case, the type of the return value and the `zd` parameter vary with the type suffix. For example, in the `_u8` intrinsic, the return value and the `zd` parameter both have type `svuint8_t`. ``` c // And similarly for u8. svint8_t svread_hor_za8[_s8]_m(svint8_t zd, svbool_t pg, uint64_t tile, uint32_t slice) __arm_streaming __arm_in("za"); // And similarly for u16, bf16 and f16. svint16_t svread_hor_za16[_s16]_m(svint16_t zd, svbool_t pg, uint64_t tile, uint32_t slice) __arm_streaming __arm_in("za"); // And similarly for u32 and f32. svint32_t svread_hor_za32[_s32]_m(svint32_t zd, svbool_t pg, uint64_t tile, uint32_t slice) __arm_streaming __arm_in("za"); // And similarly for u64 and f64. svint64_t svread_hor_za64[_s64]_m(svint64_t zd, svbool_t pg, uint64_t tile, uint32_t slice) __arm_streaming __arm_in("za"); // And similarly for s16, s32, s64, u8, u16, u32, u64, bf16, f16, f32, f64 svint8_t svread_hor_za128[_s8]_m(svint8_t zd, svbool_t pg, uint64_t tile, uint32_t slice) __arm_streaming __arm_in("za"); ``` Replacing `_hor` with `_ver` gives the associated vertical forms. The intrinsics below write to horizontal ZA slices. In each case, the type of the `zn` parameter varies with the type suffix. For example, the `zn` parameter to the `_u8` intrinsic has type `svuint8_t`. ``` c // And similarly for u8. void svwrite_hor_za8[_s8]_m(uint64_t tile, uint32_t slice, svbool_t pg, svint8_t zn) __arm_streaming __arm_inout("za"); // And similarly for u16, bf16 and f16. void svwrite_hor_za16[_s16]_m(uint64_t tile, uint32_t slice, svbool_t pg, svint16_t zn) __arm_streaming __arm_inout("za"); // And similarly for u32 and f32. void svwrite_hor_za32[_s32]_m(uint64_t tile, uint32_t slice, svbool_t pg, svint32_t zn) __arm_streaming __arm_inout("za"); // And similarly for u64 and f64. void svwrite_hor_za64[_s64]_m(uint64_t tile, uint32_t slice, svbool_t pg, svint64_t zn) __arm_streaming __arm_inout("za"); // And similarly for s16, s32, s64, u8, u16, u32, u64, bf16, f16, f32, f64 void svwrite_hor_za128[_s8]_m(uint64_t tile, uint32_t slice, svbool_t pg, svint8_t zn) __arm_streaming __arm_inout("za"); ``` Replacing `_hor` with `_ver` gives the associated vertical forms. #### ADDHA ``` c void svaddha_za32[_s32]_m(uint64_t tile, svbool_t pn, svbool_t pm, svint32_t zn) __arm_streaming __arm_inout("za"); void svaddha_za32[_u32]_m(uint64_t tile, svbool_t pn, svbool_t pm, svuint32_t zn) __arm_streaming __arm_inout("za"); // Only if __ARM_FEATURE_SME_I16I64 != 0 void svaddha_za64[_s64]_m(uint64_t tile, svbool_t pn, svbool_t pm, svint64_t zn) __arm_streaming __arm_inout("za"); // Only if __ARM_FEATURE_SME_I16I64 != 0 void svaddha_za64[_u64]_m(uint64_t tile, svbool_t pn, svbool_t pm, svuint64_t zn) __arm_streaming __arm_inout("za"); ``` #### ADDVA ``` c void svaddva_za32[_s32]_m(uint64_t tile, svbool_t pn, svbool_t pm, svint32_t zn) __arm_streaming __arm_inout("za"); void svaddva_za32[_u32]_m(uint64_t tile, svbool_t pn, svbool_t pm, svuint32_t zn) __arm_streaming __arm_inout("za"); // Only if __ARM_FEATURE_SME_I16I64 != 0 void svaddva_za64[_s64]_m(uint64_t tile, svbool_t pn, svbool_t pm, svint64_t zn) __arm_streaming __arm_inout("za"); // Only if __ARM_FEATURE_SME_I16I64 != 0 void svaddva_za64[_u64]_m(uint64_t tile, svbool_t pn, svbool_t pm, svuint64_t zn) __arm_streaming __arm_inout("za"); ``` #### BFMOPA, FMOPA (widening), SMOPA, UMOPA ``` c void svmopa_za32[_bf16]_m(uint64_t tile, svbool_t pn, svbool_t pm, svbfloat16_t zn, svbfloat16_t zm) __arm_streaming __arm_inout("za"); void svmopa_za32[_f16]_m(uint64_t tile, svbool_t pn, svbool_t pm, svfloat16_t zn, svfloat16_t zm) __arm_streaming __arm_inout("za"); void svmopa_za32[_s8]_m(uint64_t tile, svbool_t pn, svbool_t pm, svint8_t zn, svint8_t zm) __arm_streaming; void svmopa_za32[_u8]_m(uint64_t tile, svbool_t pn, svbool_t pm, svuint8_t zn, svuint8_t zm) __arm_streaming __arm_inout("za"); // Only if __ARM_FEATURE_SME_I16I64 != 0 void svmopa_za64[_s16]_m(uint64_t tile, svbool_t pn, svbool_t pm, svint16_t zn, svint16_t zm) __arm_streaming __arm_inout("za"); // Only if __ARM_FEATURE_SME_I16I64 != 0 void svmopa_za64[_u16]_m(uint64_t tile, svbool_t pn, svbool_t pm, svuint16_t zn, svuint16_t zm) __arm_streaming __arm_inout("za"); ``` #### FMOPA (non-widening) ``` c void svmopa_za32[_f32]_m(uint64_t tile, svbool_t pn, svbool_t pm, svfloat32_t zn, svfloat32_t zm) __arm_streaming __arm_inout("za"); // Only if __ARM_FEATURE_SME_F64F64 != 0 void svmopa_za64[_f64]_m(uint64_t tile, svbool_t pn, svbool_t pm, svfloat64_t zn, svfloat64_t zm) __arm_streaming __arm_inout("za"); ``` #### BFMOPS, FMOPS (widening), SMOPS, UMOPS ``` c void svmops_za32[_bf16]_m(uint64_t tile, svbool_t pn, svbool_t pm, svbfloat16_t zn, svbfloat16_t zm) __arm_streaming __arm_inout("za"); void svmops_za32[_f16]_m(uint64_t tile, svbool_t pn, svbool_t pm, svfloat16_t zn, svfloat16_t zm) __arm_streaming __arm_inout("za"); void svmops_za32[_s8]_m(uint64_t tile, svbool_t pn, svbool_t pm, svint8_t zn, svint8_t zm) __arm_streaming __arm_inout("za"); void svmops_za32[_u8]_m(uint64_t tile, svbool_t pn, svbool_t pm, svuint8_t zn, svuint8_t zm) __arm_streaming __arm_inout("za"); // Only if __ARM_FEATURE_SME_I16I64 != 0 void svmops_za64[_s16]_m(uint64_t tile, svbool_t pn, svbool_t pm, svint16_t zn, svint16_t zm) __arm_streaming __arm_inout("za"); // Only if __ARM_FEATURE_SME_I16I64 != 0 void svmops_za64[_u16]_m(uint64_t tile, svbool_t pn, svbool_t pm, svuint16_t zn, svuint16_t zm) __arm_streaming __arm_inout("za"); ``` #### FMOPS (non-widening) ``` c void svmops_za32[_f32]_m(uint64_t tile, svbool_t pn, svbool_t pm, svfloat32_t zn, svfloat32_t zm) __arm_streaming __arm_inout("za"); // Only if __ARM_FEATURE_SME_F64F64 != 0 void svmops_za64[_f64]_m(uint64_t tile, svbool_t pn, svbool_t pm, svfloat64_t zn, svfloat64_t zm) __arm_streaming __arm_inout("za"); ``` #### RDSVL The following intrinsics read the length of a streaming vector: ``` c // Return the number of bytes in a streaming vector. // Equivalent to svcntb() when called in streaming mode. uint64_t svcntsb() __arm_streaming_compatible; // Return the number of halfwords in a streaming vector. // Equivalent to svcnth() when called in streaming mode. uint64_t svcntsh() __arm_streaming_compatible; // Return the number of words in a streaming vector. // Equivalent to svcntw() when called in streaming mode. uint64_t svcntsw() __arm_streaming_compatible; // Return the number of doublewords in a streaming vector. // Equivalent to svcntd() when called in streaming mode. uint64_t svcntsd() __arm_streaming_compatible; ``` `svcntsb()` is equivalent to an RDSVL instruction with an immediate operand of 1. There are no intrinsics that map directly to other immediate operands, or to the ADDSVL and ADDSPL instructions, but it is possible to write these operations using normal C arithmetic. For example: ``` c x0 = svcntsb(); // corresponds to RDSVL x0, #1 x0 = svcntsb() * 5; // can be optimized to RDSVL x0, #5 x0 = x1 + svcntsb(); // can be optimized to ADDSVL x0, x1, #1 x0 = x1 - svcntsb() * 3; // can be optimized to ADDSVL x0, x1, #-3 x0 = x1 + svcntsd(); // can be optimized to ADDSPL x0, x1, #1 x0 = x1 - svcntsw(); // can be optimized to ADDSPL x0, x1, #-2 ``` #### SUMOPA ``` c void svsumopa_za32[_s8]_m(uint64_t tile, svbool_t pn, svbool_t pm, svint8_t zn, svuint8_t zm) __arm_streaming __arm_inout("za"); // Only if __ARM_FEATURE_SME_I16I64 != 0 void svsumopa_za64[_s16]_m(uint64_t tile, svbool_t pn, svbool_t pm, svint16_t zn, svuint16_t zm) __arm_streaming __arm_inout("za"); ``` #### SUMOPS ``` c void svsumops_za32[_s8]_m(uint64_t tile, svbool_t pn, svbool_t pm, svint8_t zn, svuint8_t zm) __arm_streaming __arm_inout("za"); // Only if __ARM_FEATURE_SME_I16I64 != 0 void svsumops_za64[_s16]_m(uint64_t tile, svbool_t pn, svbool_t pm, svint16_t zn, svuint16_t zm) __arm_streaming __arm_inout("za"); ``` #### USMOPA ``` c void svusmopa_za32[_u8]_m(uint64_t tile, svbool_t pn, svbool_t pm, svuint8_t zn, svint8_t zm) __arm_streaming __arm_inout("za"); // Only if __ARM_FEATURE_SME_I16I64 != 0 void svusmopa_za64[_u16]_m(uint64_t tile, svbool_t pn, svbool_t pm, svuint16_t zn, svint16_t zm) __arm_streaming __arm_inout("za"); ``` #### USMOPS ``` c void svusmops_za32[_u8]_m(uint64_t tile, svbool_t pn, svbool_t pm, svuint8_t zn, svint8_t zm) __arm_streaming __arm_inout("za"); // Only if __ARM_FEATURE_SME_I16I64 != 0 void svusmops_za64[_u16]_m(uint64_t tile, svbool_t pn, svbool_t pm, svuint16_t zn, svint16_t zm) __arm_streaming __arm_inout("za"); ``` #### ZERO ``` c void svzero_mask_za(uint64_t tile_mask) __arm_streaming_compatible __arm_inout("za"); void svzero_za() __arm_streaming_compatible __arm_out("za"); ``` ### SME2 instruction intrinsics The intrinsics in this section are defined by the header file [``](#arm_sme.h) when `__ARM_FEATURE_SME2` is defined. #### ADD, SUB (store into ZA, single) Multi-vector add/sub, storing into ZA The additional '_write' suffix indicates that the operation is not accumulating; the result is written directly into ZA. ``` c // Variants are available for: // _za32[_s32] // _za32[_u32] // _za64[_s64] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u64] (only if __ARM_FEATURE_SME_I16I64 != 0) void svadd_write[_single]_za32[_s32]_vg1x2(uint32_t slice, svint32x2_t zn, svint32_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_s32] // _za32[_u32] // _za64[_s64] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u64] (only if __ARM_FEATURE_SME_I16I64 != 0) void svadd_write[_single]_za32[_s32]_vg1x4(uint32_t slice, svint32x4_t zn, svint32_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_s32] // _za32[_u32] // _za64[_s64] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u64] (only if __ARM_FEATURE_SME_I16I64 != 0) void svsub_write[_single]_za32[_u32]_vg1x2(uint32_t slice, svuint32x2_t zn, svuint32_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_s32] // _za32[_u32] // _za64[_s64] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u64] (only if __ARM_FEATURE_SME_I16I64 != 0) void svsub_write[_single]_za32[_u32]_vg1x4(uint32_t slice, svuint32x4_t zn, svuint32_t zm) __arm_streaming __arm_inout("za"); ``` #### ADD, SUB (store into ZA, multi) Multi-vector add/sub, storing into ZA The additional '_write' suffix indicates that the operation is not accumulating; the result is written directly into ZA. ``` c // Variants are available for: // _za32[_s32] // _za32[_u32] // _za64[_s64] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u64] (only if __ARM_FEATURE_SME_I16I64 != 0) void svadd_write_za32[_s32]_vg1x2(uint32_t slice, svint32x2_t zn, svint32x2_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_s32] // _za32[_u32] // _za64[_s64] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u64] (only if __ARM_FEATURE_SME_I16I64 != 0) void svadd_write_za32[_s32]_vg1x4(uint32_t slice, svint32x4_t zn, svint32x4_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_s32] // _za32[_u32] // _za64[_s64] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u64] (only if __ARM_FEATURE_SME_I16I64 != 0) void svsub_write_za32[_u32]_vg1x2(uint32_t slice, svuint32x2_t zn, svuint32x2_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_s32] // _za32[_u32] // _za64[_s64] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u64] (only if __ARM_FEATURE_SME_I16I64 != 0) void svsub_write_za32[_u32]_vg1x4(uint32_t slice, svuint32x4_t zn, svuint32x4_t zm) __arm_streaming __arm_inout("za"); ``` #### ADD (vectors) Multi-vector add ``` c // Variants are also available for _single_u8_x2, _single_s16_x2, // _single_u16_x2, _single_s32_x2, _single_u32_x2, _single_s64_x2 and // _single_u64_x2 svint8x2_t svadd[_single_s8_x2](svint8x2_t zdn, svint8_t zm) __arm_streaming; // Variants are also available for _single_u8_x4, _single_s16_x4, // _single_u16_x4, _single_s32_x4, _single_u32_x4, _single_s64_x4 and // _single_u64_x4 svint8x4_t svadd[_single_s8_x4](svint8x4_t zdn, svint8_t zm) __arm_streaming; ``` #### ADD, SUB, FADD, FSUB (accumulate into ZA) Multi-vector add/sub and accumulate into ZA ``` c // Variants are available for: // _za32[_f32] // _za32[_s32] // _za32[_u32] // _za64[_f64] (only if __ARM_FEATURE_SME_F64F64 != 0) // _za64[_s64] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u64] (only if __ARM_FEATURE_SME_I16I64 != 0) void svadd_za32[_f32]_vg1x2(uint32_t slice, svfloat32x2_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_f32] // _za32[_s32] // _za32[_u32] // _za64[_f64] (only if __ARM_FEATURE_SME_F64F64 != 0) // _za64[_s64] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u64] (only if __ARM_FEATURE_SME_I16I64 != 0) void svadd_za32[_f32]_vg1x4(uint32_t slice, svfloat32x4_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_f32] // _za32[_s32] // _za32[_u32] // _za64[_f64] (only if __ARM_FEATURE_SME_F64F64 != 0) // _za64[_s64] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u64] (only if __ARM_FEATURE_SME_I16I64 != 0) void svsub_za32[_f32]_vg1x2(uint32_t slice, svfloat32x2_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_f32] // _za32[_s32] // _za32[_u32] // _za64[_f64] (only if __ARM_FEATURE_SME_F64F64 != 0) // _za64[_s64] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u64] (only if __ARM_FEATURE_SME_I16I64 != 0) void svsub_za32[_f32]_vg1x4(uint32_t slice, svfloat32x4_t zm) __arm_streaming __arm_inout("za"); ``` #### BFCVTN, FCVTN Multi-vector floating-point convert from single-precision to interleaved half-precision/BFloat16 ``` c // Variants are also available for _f16[_f32_x2] svbfloat16_t svcvtn_bf16[_f32_x2](svfloat32x2_t zn) __arm_streaming; ``` #### FCVT, BFCVT, FCVTZS, FCVTZU, SCVTF, UCVTF Multi-vector convert to/from floating-point. ``` c // Variants are also available for _f16[_f32_x2] svbfloat16_t svcvt_bf16[_f32_x2](svfloat32x2_t zn) __arm_streaming; // Variants are also available for _f32[_u32_x2], _s32[_f32_x2] and _u32[_f32_x2] svfloat32x2_t svcvt_f32[_s32_x2](svint32x2_t zn) __arm_streaming; // Variants are also available for _f32[_u32_x4], _s32[_f32_x4] and _u32[_f32_x4] svfloat32x4_t svcvt_f32[_s32_x4](svint32x4_t zn) __arm_streaming; ``` #### SQCVT, SQCVTU, UQCVT Multi-vector saturating extract narrow ``` c // Variants are also available for _u16[_s32_x2] and _u16[_u32_x2] svint16_t svqcvt_s16[_s32_x2](svint32x2_t zn) __arm_streaming; // Variants are also available for _u8[_s32_x4], _u8[_u32_x4], _s16[_s64_x4], // _u16[_s64_x4] and _u16[_u64_x4] svint8_t svqcvt_s8[_s32_x4](svint32x4_t zn) __arm_streaming; ``` #### SQCVTN, SQCVTUN, UQCVTN Multi-vector saturating extract narrow and interleave ``` c // Variants are also available for _u8[_s32_x4], _u8[_u32_x4], _s16[_s64_x4], // _u16[_s64_x4] and _u16[_u64_x4] svint8_t svqcvtn_s8[_s32_x4](svint32x4_t zn) __arm_streaming; ``` #### FDOT, BFDOT, SUDOT, USDOT, SDOT, UDOT (store into ZA, single) Multi-vector dot-product (2-way and 4-way) ``` c // Variants are available for: // _za32[_bf16] // _za32[_f16] // _za32[_s8] // _za32[_s16] // _za32[_u8] // _za32[_u16] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svdot[_single]_za32[_bf16]_vg1x2(uint32_t slice, svbfloat16x2_t zn, svbfloat16_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_bf16] // _za32[_f16] // _za32[_s8] // _za32[_s16] // _za32[_u8] // _za32[_u16] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svdot[_single]_za32[_bf16]_vg1x4(uint32_t slice, svbfloat16x4_t zn, svbfloat16_t zm) __arm_streaming __arm_inout("za"); void svsudot[_single]_za32[_s8]_vg1x2(uint32_t slice, svint8x2_t zn, svuint8_t zm) __arm_streaming __arm_inout("za"); void svsudot[_single]_za32[_s8]_vg1x4(uint32_t slice, svint8x4_t zn, svuint8_t zm) __arm_streaming __arm_inout("za"); void svusdot[_single]_za32[_u8]_vg1x2(uint32_t slice, svuint8x2_t zn, svint8_t zm) __arm_streaming __arm_inout("za"); void svusdot[_single]_za32[_u8]_vg1x4(uint32_t slice, svuint8x4_t zn, svint8_t zm) __arm_streaming __arm_inout("za"); ``` #### FDOT, BFDOT, SUDOT, USDOT, SDOT, UDOT (store into ZA, multi) Multi-vector dot-product (2-way and 4-way) ``` c // Variants are available for: // _za32[_bf16] // _za32[_f16] // _za32[_s8] // _za32[_s16] // _za32[_u8] // _za32[_u16] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svdot_za32[_bf16]_vg1x2(uint32_t slice, svbfloat16x2_t zn, svbfloat16x2_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_bf16] // _za32[_f16] // _za32[_s8] // _za32[_s16] // _za32[_u8] // _za32[_u16] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svdot_za32[_bf16]_vg1x4(uint32_t slice, svbfloat16x4_t zn, svbfloat16x4_t zm) __arm_streaming __arm_inout("za"); void svsudot_za32[_s8]_vg1x2(uint32_t slice, svint8x2_t zn, svuint8x2_t zm) __arm_streaming __arm_inout("za"); void svsudot_za32[_s8]_vg1x4(uint32_t slice, svint8x4_t zn, svuint8x4_t zm) __arm_streaming __arm_inout("za"); void svusdot_za32[_u8]_vg1x2(uint32_t slice, svuint8x2_t zn, svint8x2_t zm) __arm_streaming __arm_inout("za"); void svusdot_za32[_u8]_vg1x4(uint32_t slice, svuint8x4_t zn, svint8x4_t zm) __arm_streaming __arm_inout("za"); ``` #### FDOT, BFDOT, SUDOT, USDOT, SDOT, UDOT (store into ZA, indexed) Multi-vector dot-product (2-way and 4-way) ``` c // Variants are available for: // _za32[_bf16] // _za32[_f16] // _za32[_s8] // _za32[_s16] // _za32[_u8] // _za32[_u16] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svdot_lane_za32[_bf16]_vg1x2(uint32_t slice, svbfloat16x2_t zn, svbfloat16_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_bf16] // _za32[_f16] // _za32[_s8] // _za32[_s16] // _za32[_u8] // _za32[_u16] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svdot_lane_za32[_bf16]_vg1x4(uint32_t slice, svbfloat16x4_t zn, svbfloat16_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); void svsudot_lane_za32[_s8]_vg1x2(uint32_t slice, svint8x2_t zn, svuint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); void svsudot_lane_za32[_s8]_vg1x4(uint32_t slice, svint8x4_t zn, svuint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); void svusdot_lane_za32[_u8]_vg1x2(uint32_t slice, svuint8x2_t zn, svint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); void svusdot_lane_za32[_u8]_vg1x4(uint32_t slice, svuint8x4_t zn, svint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); ``` #### FVDOT, BFVDOT, SUVDOT, USVDOT, SVDOT, UVDOT Multi-vector vertical dot-product by indexed element. ``` c void svsuvdot_lane_za32[_s8]_vg1x4(uint32_t slice, svint8x4_t zn, svuint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); void svusvdot_lane_za32[_u8]_vg1x4(uint32_t slice, svuint8x4_t zn, svint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); // Variants are also available for _za32[_f16], _za32[_s16] and _za32[_u16] void svvdot_lane_za32[_bf16]_vg1x2(uint32_t slice, svbfloat16x2_t zn, svbfloat16_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_s8] // _za32[_u8] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svvdot_lane_za32[_s8]_vg1x4(uint32_t slice, svint8x4_t zn, svint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); ``` #### UMOPA, SMOPA, UMOPS, SMOPS Integer sum of outer products and accumulate/subtract (2-way) ``` c // Variants are also available for _za32[_u16] void svmopa_za32[_s16]_m(uint64_t tile, svbool_t pn, svbool_t pm, svint16_t zn, svint16_t zm) __arm_streaming __arm_inout("za"); // Variants are also available for _za32[_u16] void svmops_za32[_s16]_m(uint64_t tile, svbool_t pn, svbool_t pm, svint16_t zn, svint16_t zm) __arm_streaming __arm_inout("za"); ``` #### BMOPA, BMOPS Bitwise exclusive NOR population count outer product and accumulate/subtract ``` c // Variants are also available for _za32[_s32] void svbmopa_za32[_u32]_m(uint64_t tile, svbool_t pn, svbool_t pm, svuint32_t zn, svuint32_t zm) __arm_streaming __arm_inout("za"); // Variants are also available for _za32[_s32] void svbmops_za32[_u32]_m(uint64_t tile, svbool_t pn, svbool_t pm, svuint32_t zn, svuint32_t zm) __arm_streaming __arm_inout("za"); ``` #### FMLA, FMLS (single) Multi-vector floating-point fused multiply-add/subtract ``` c // Variants are available for: // _za32[_f32] // _za64[_f64] (only if __ARM_FEATURE_SME_F64F64 != 0) void svmla[_single]_za32[_f32]_vg1x2(uint32_t slice, svfloat32x2_t zn, svfloat32_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_f32] // _za64[_f64] (only if __ARM_FEATURE_SME_F64F64 != 0) void svmla[_single]_za32[_f32]_vg1x4(uint32_t slice, svfloat32x4_t zn, svfloat32_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_f32] // _za64[_f64] (only if __ARM_FEATURE_SME_F64F64 != 0) void svmls[_single]_za32[_f32]_vg1x2(uint32_t slice, svfloat32x2_t zn, svfloat32_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_f32] // _za64[_f64] (only if __ARM_FEATURE_SME_F64F64 != 0) void svmls[_single]_za32[_f32]_vg1x4(uint32_t slice, svfloat32x4_t zn, svfloat32_t zm) __arm_streaming __arm_inout("za"); ``` #### FMLA, FMLS (multi) Multi-vector floating-point fused multiply-add/subtract ``` c // Variants are available for: // _za32[_f32] // _za64[_f64] (only if __ARM_FEATURE_SME_F64F64 != 0) void svmla_za32[_f32]_vg1x2(uint32_t slice, svfloat32x2_t zn, svfloat32x2_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_f32] // _za64[_f64] (only if __ARM_FEATURE_SME_F64F64 != 0) void svmla_za32[_f32]_vg1x4(uint32_t slice, svfloat32x4_t zn, svfloat32x4_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_f32] // _za64[_f64] (only if __ARM_FEATURE_SME_F64F64 != 0) void svmls_za32[_f32]_vg1x2(uint32_t slice, svfloat32x2_t zn, svfloat32x2_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_f32] // _za64[_f64] (only if __ARM_FEATURE_SME_F64F64 != 0) void svmls_za32[_f32]_vg1x4(uint32_t slice, svfloat32x4_t zn, svfloat32x4_t zm) __arm_streaming __arm_inout("za"); ``` #### FMLA, FMLS (indexed) Multi-vector floating-point fused multiply-add/subtract ``` c // Variants are available for: // _za32[_f32] // _za64[_f64] (only if __ARM_FEATURE_SME_F64F64 != 0) void svmla_lane_za32[_f32]_vg1x2(uint32_t slice, svfloat32x2_t zn, svfloat32_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_f32] // _za64[_f64] (only if __ARM_FEATURE_SME_F64F64 != 0) void svmla_lane_za32[_f32]_vg1x4(uint32_t slice, svfloat32x4_t zn, svfloat32_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_f32] // _za64[_f64] (only if __ARM_FEATURE_SME_F64F64 != 0) void svmls_lane_za32[_f32]_vg1x2(uint32_t slice, svfloat32x2_t zn, svfloat32_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_f32] // _za64[_f64] (only if __ARM_FEATURE_SME_F64F64 != 0) void svmls_lane_za32[_f32]_vg1x4(uint32_t slice, svfloat32x4_t zn, svfloat32_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); ``` #### FMLAL, BFMLAL, SMLAL, UMLAL (single) Multi-vector multiply-add long (widening) ``` c // Variants are also available for _za32[_f16], _za32[_s16] and _za32[_u16] void svmla_za32[_bf16]_vg2x1(uint32_t slice, svbfloat16_t zn, svbfloat16_t zm) __arm_streaming __arm_inout("za"); // Variants are also available for _za32[_f16], _za32[_s16] and _za32[_u16] void svmla[_single]_za32[_bf16]_vg2x2(uint32_t slice, svbfloat16x2_t zn, svbfloat16_t zm) __arm_streaming __arm_inout("za"); // Variants are also available for _za32[_f16], _za32[_s16] and _za32[_u16] void svmla[_single]_za32[_bf16]_vg2x4(uint32_t slice, svbfloat16x4_t zn, svbfloat16_t zm) __arm_streaming __arm_inout("za"); ``` #### FMLAL, BFMLAL, SMLAL, UMLAL (multi) Multi-vector multiply-add long (widening) ``` c // Variants are also available for _za32[_f16], _za32[_s16] and _za32[_u16] void svmla_za32[_bf16]_vg2x2(uint32_t slice, svbfloat16x2_t zn, svbfloat16x2_t zm) __arm_streaming __arm_inout("za"); // Variants are also available for _za32[_f16], _za32[_s16] and _za32[_u16] void svmla_za32[_bf16]_vg2x4(uint32_t slice, svbfloat16x4_t zn, svbfloat16x4_t zm) __arm_streaming __arm_inout("za"); ``` #### FMLAL, BFMLAL, SMLAL, UMLAL (indexed) Multi-vector multiply-add long (widening) ``` c // Variants are also available for _za32[_f16], _za32[_s16] and _za32[_u16] void svmla_lane_za32[_bf16]_vg2x1(uint32_t slice, svbfloat16_t zn, svbfloat16_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); // Variants are also available for _za32[_f16], _za32[_s16] and _za32[_u16] void svmla_lane_za32[_bf16]_vg2x2(uint32_t slice, svbfloat16x2_t zn, svbfloat16_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); // Variants are also available for _za32[_f16], _za32[_s16] and _za32[_u16] void svmla_lane_za32[_bf16]_vg2x4(uint32_t slice, svbfloat16x4_t zn, svbfloat16_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); ``` #### BFMLSL, FMLSL, UMLSL, SMLSL (single) Multi-vector multiply-subtract long (widening) ``` c // Variants are also available for _za32[_f16], _za32[_s16] and _za32[_u16] void svmls_za32[_bf16]_vg2x1(uint32_t slice, svbfloat16_t zn, svbfloat16_t zm) __arm_streaming __arm_inout("za"); // Variants are also available for _za32[_f16], _za32[_s16] and _za32[_u16] void svmls[_single]_za32[_bf16]_vg2x2(uint32_t slice, svbfloat16x2_t zn, svbfloat16_t zm) __arm_streaming __arm_inout("za"); // Variants are also available for _za32[_f16], _za32[_s16] and _za32[_u16] void svmls[_single]_za32[_bf16]_vg2x4(uint32_t slice, svbfloat16x4_t zn, svbfloat16_t zm) __arm_streaming __arm_inout("za"); ``` #### BFMLSL, FMLSL, UMLSL, SMLSL (multi) Multi-vector multiply-subtract long (widening) ``` c // Variants are also available for _za32[_f16], _za32[_s16] and _za32[_u16] void svmls_za32[_bf16]_vg2x2(uint32_t slice, svbfloat16x2_t zn, svbfloat16x2_t zm) __arm_streaming __arm_inout("za"); // Variants are also available for _za32[_f16], _za32[_s16] and _za32[_u16] void svmls_za32[_bf16]_vg2x4(uint32_t slice, svbfloat16x4_t zn, svbfloat16x4_t zm) __arm_streaming __arm_inout("za"); ``` #### BFMLSL, FMLSL, UMLSL, SMLSL (indexed) Multi-vector multiply-subtract long (widening) ``` c // Variants are also available for _za32[_f16], _za32[_s16] and _za32[_u16] void svmls_lane_za32[_bf16]_vg2x1(uint32_t slice, svbfloat16_t zn, svbfloat16_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); // Variants are also available for _za32[_f16], _za32[_s16] and _za32[_u16] void svmls_lane_za32[_bf16]_vg2x2(uint32_t slice, svbfloat16x2_t zn, svbfloat16_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); // Variants are also available for _za32[_f16], _za32[_s16] and _za32[_u16] void svmls_lane_za32[_bf16]_vg2x4(uint32_t slice, svbfloat16x4_t zn, svbfloat16_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); ``` #### UMLALL, SMLALL, USMLALL, SUMLALL (single) Multi-vector multiply-add long long (widening) ``` c // Variants are available for: // _za32[_s8] // _za32[_u8] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svmla_za32[_s8]_vg4x1(uint32_t slice, svint8_t zn, svint8_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_s8] // _za32[_u8] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svmla[_single]_za32[_s8]_vg4x2(uint32_t slice, svint8x2_t zn, svint8_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_s8] // _za32[_u8] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svmla[_single]_za32[_s8]_vg4x4(uint32_t slice, svint8x4_t zn, svint8_t zm) __arm_streaming __arm_inout("za"); void svsumla_za32[_s8]_vg4x1(uint32_t slice, svint8_t zn, svuint8_t zm) __arm_streaming __arm_inout("za"); void svsumla[_single]_za32[_s8]_vg4x2(uint32_t slice, svint8x2_t zn, svuint8_t zm) __arm_streaming __arm_inout("za"); void svsumla[_single]_za32[_s8]_vg4x4(uint32_t slice, svint8x4_t zn, svuint8_t zm) __arm_streaming __arm_inout("za"); void svusmla_za32[_u8]_vg4x1(uint32_t slice, svuint8_t zn, svint8_t zm) __arm_streaming __arm_inout("za"); void svusmla[_single]_za32[_u8]_vg4x2(uint32_t slice, svuint8x2_t zn, svint8_t zm) __arm_streaming __arm_inout("za"); void svusmla[_single]_za32[_u8]_vg4x4(uint32_t slice, svuint8x4_t zn, svint8_t zm) __arm_streaming __arm_inout("za"); ``` #### UMLALL, SMLALL, USMLALL, SUMLALL (multi) Multi-vector multiply-add long long (widening) ``` c // Variants are available for: // _za32[_s8] // _za32[_u8] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svmla_za32[_s8]_vg4x2(uint32_t slice, svint8x2_t zn, svint8x2_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_s8] // _za32[_u8] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svmla_za32[_s8]_vg4x4(uint32_t slice, svint8x4_t zn, svint8x4_t zm) __arm_streaming __arm_inout("za"); void svsumla_za32[_s8]_vg4x2(uint32_t slice, svint8x2_t zn, svuint8x2_t zm) __arm_streaming __arm_inout("za"); void svsumla_za32[_s8]_vg4x4(uint32_t slice, svint8x4_t zn, svuint8x4_t zm) __arm_streaming __arm_inout("za"); void svusmla_za32[_u8]_vg4x2(uint32_t slice, svuint8x2_t zn, svint8x2_t zm) __arm_streaming __arm_inout("za"); void svusmla_za32[_u8_vg4x4(uint32_t slice, svuint8x4_t zn, svint8x4_t zm) __arm_streaming __arm_inout("za"); ``` #### UMLALL, SMLALL, USMLALL, SUMLALL (indexed) Multi-vector multiply-add long long (widening) ``` c // Variants are available for: // _za32[_s8] // _za32[_u8] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svmla_lane_za32[_s8]_vg4x1(uint32_t slice, svint8_t zn, svint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_s8] // _za32[_u8] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svmla_lane_za32[_s8]_vg4x2(uint32_t slice, svint8x2_t zn, svint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_s8] // _za32[_u8] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svmla_lane_za32[_s8]_vg4x4(uint32_t slice, svint8x4_t zn, svint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); void svsumla_lane_za32[_s8]_vg4x1(uint32_t slice, svint8_t zn, svuint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); void svsumla_lane_za32[_s8]_vg4x2(uint32_t slice, svint8x2_t zn, svuint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); void svsumla_lane_za32[_s8]_vg4x4(uint32_t slice, svint8x4_t zn, svuint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); void svusmla_lane_za32[_u8]_vg4x1(uint32_t slice, svuint8_t zn, svint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); void svusmla_lane_za32[_u8]_vg4x2(uint32_t slice, svuint8x2_t zn, svint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); void svusmla_lane_za32[_u8]_vg4x4(uint32_t slice, svuint8x4_t zn, svint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); ``` #### SMLSLL, UMLSLL (single) Multi-vector multiply-subtract long long (widening) ``` c // Variants are available for: // _za32[_s8] // _za32[_u8] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svmls_za32[_s8]_vg4x1(uint32_t slice, svint8_t zn, svint8_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_s8] // _za32[_u8] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svmls[_single]_za32[_s8]_vg4x2(uint32_t slice, svint8x2_t zn, svint8_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_s8] // _za32[_u8] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svmls[_single]_za32[_s8]_vg4x4(uint32_t slice, svint8x4_t zn, svint8_t zm) __arm_streaming __arm_inout("za"); ``` #### SMLSLL, UMLSLL (multi) Multi-vector multiply-subtract long long (widening) ``` c // Variants are available for: // _za32[_s8] // _za32[_u8] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svmls_za32[_s8]_vg4x2(uint32_t slice, svint8x2_t zn, svint8x2_t zm) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_s8] // _za32[_u8] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svmls_za32[_s8]_vg4x4(uint32_t slice, svint8x4_t zn, svint8x4_t zm) __arm_streaming __arm_inout("za"); ``` #### SMLSLL, UMLSLL (indexed) Multi-vector multiply-subtract long long (widening) ``` c // Variants are available for: // _za32[_s8] // _za32[_u8] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svmls_lane_za32[_s8]_vg4x1(uint32_t slice, svint8_t zn, svint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_s8] // _za32[_u8] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svmls_lane_za32[_s8]_vg4x2(uint32_t slice, svint8x2_t zn, svint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); // Variants are available for: // _za32[_s8] // _za32[_u8] // _za64[_s16] (only if __ARM_FEATURE_SME_I16I64 != 0) // _za64[_u16] (only if __ARM_FEATURE_SME_I16I64 != 0) void svmls_lane_za32[_s8]_vg4x4(uint32_t slice, svint8x4_t zn, svint8_t zm, uint64_t imm_idx) __arm_streaming __arm_inout("za"); ``` #### SMAX, SMIN, UMAX, UMIN, FMAX, FMIN (single) Multi-vector min/max ``` c // Variants are also available for _single_s8_x2, _single_u8_x2, // _single_s16_x2, _single_u16_x2, _single_s32_x2, _single_u32_x2, // _single_f32_x2, _single_s64_x2, _single_u64_x2 and _single_f64_x2 svfloat16x2_t svmax[_single_f16_x2](svfloat16x2_t zdn, svfloat16_t zm) __arm_streaming; // Variants are also available for _single_s8_x4, _single_u8_x4, // _single_s16_x4, _single_u16_x4, _single_s32_x4, _single_u32_x4, // _single_f32_x4, _single_s64_x4, _single_u64_x4 and _single_f64_x4 svfloat16x4_t svmax[_single_f16_x4](svfloat16x4_t zdn, svfloat16_t zm) __arm_streaming; // Variants are also available for _single_s8_x2, _single_u8_x2, // _single_s16_x2, _single_u16_x2, _single_s32_x2, _single_u32_x2, // _single_f32_x2, _single_s64_x2, _single_u64_x2 and _single_f64_x2 svfloat16x2_t svmin[_single_f16_x2](svfloat16x2_t zdn, svfloat16_t zm) __arm_streaming; // Variants are also available for _single_s8_x4, _single_u8_x4, // _single_s16_x4, _single_u16_x4, _single_s32_x4, _single_u32_x4, // _single_f32_x4, _single_s64_x4, _single_u64_x4 and _single_f64_x4 svfloat16x4_t svmin[_single_f16_x4](svfloat16x4_t zdn, svfloat16_t zm) __arm_streaming; ``` #### SMAX, SMIN, UMAX, UMIN, FMAX, FMIN (multi) Multi-vector min/max ``` c // Variants are also available for _s8_x2, _u8_x2, _s16_x2, _u16_x2, // _s32_x2, _u32_x2, _f32_x2, _s64_x2, _u64_x2 and _f64_x2 svfloat16x2_t svmax[_f16_x2](svfloat16x2_t zdn, svfloat16x2_t zm) __arm_streaming; // Variants are also available for _s8_x4, _u8_x4, _s16_x4, _u16_x4, // _s32_x4, _u32_x4, _f32_x4, _s64_x4, _u64_x4 and _f64_x4 svfloat16x4_t svmax[_f16_x4](svfloat16x4_t zdn, svfloat16x4_t zm) __arm_streaming; // Variants are also available for _s8_x2, _u8_x2, _s16_x2, _u16_x2, // _s32_x2, _u32_x2, _f32_x2, _s64_x2, _u64_x2 and _f64_x2 svfloat16x2_t svmin[_f16_x2](svfloat16x2_t zdn, svfloat16x2_t zm) __arm_streaming; // Variants are also available for _s8_x4, _u8_x4, _s16_x4, _u16_x4, // _s32_x4, _u32_x4, _f32_x4, _s64_x4,_u64_x4 and _f64_x4 svfloat16x4_t svmin[_f16_x4](svfloat16x4_t zdn, svfloat16x4_t zm) __arm_streaming; ``` #### FMAXNM, FMINNM (single) Multi-vector floating point min/max number ``` c // Variants are also available for _single_f32_x2 and _single_f64_x2 svfloat16x2_t svmaxnm[_single_f16_x2](svfloat16x2_t zdn, svfloat16_t zm) __arm_streaming; // Variants are also available for _single_f32_x4 and _single_f64_x4 svfloat16x4_t svmaxnm[_single_f16_x4](svfloat16x4_t zdn, svfloat16_t zm) __arm_streaming; // Variants are also available for _single_f32_x2 and _single_f64_x2 svfloat16x2_t svminnm[_single_f16_x2](svfloat16x2_t zdn, svfloat16_t zm) __arm_streaming; // Variants are also available for _single_f32_x4 and _single_f64_x4 svfloat16x4_t svminnm[_single_f16_x4](svfloat16x4_t zdn, svfloat16_t zm) __arm_streaming; ``` #### FMAXNM, FMINNM (multi) Multi-vector floating point min/max number ``` c // Variants are also available for _f32_x2 and _f64_x2 svfloat16x2_t svmaxnm[_f16_x2](svfloat16x2_t zdn, svfloat16x2_t zm) __arm_streaming; // Variants are also available for _f32_x4 and _f64_x4 svfloat16x4_t svmaxnm[_f16_x4](svfloat16x4_t zdn, svfloat16x4_t zm) __arm_streaming; // Variants are also available for _f32_x2 and _f64_x2 svfloat16x2_t svminnm[_f16_x2](svfloat16x2_t zdn, svfloat16x2_t zm) __arm_streaming; // Variants are also available for _f32_x4 and _f64_x4 svfloat16x4_t svminnm[_f16_x4](svfloat16x4_t zdn, svfloat16x4_t zm) __arm_streaming; ``` #### FRINTA, FRINTM, FRINTN, FRINTP Multi-vector floating-point round to integral value ``` c svfloat32x2_t svrinta[_f32_x2](svfloat32x2_t zn) __arm_streaming; svfloat32x4_t svrinta[_f32_x4](svfloat32x4_t zn) __arm_streaming; svfloat32x2_t svrintm[_f32_x2](svfloat32x2_t zn) __arm_streaming; svfloat32x4_t svrintm[_f32_x4](svfloat32x4_t zn) __arm_streaming; svfloat32x2_t svrintn[_f32_x2](svfloat32x2_t zn) __arm_streaming; svfloat32x4_t svrintn[_f32_x4](svfloat32x4_t zn) __arm_streaming; svfloat32x2_t svrintp[_f32_x2](svfloat32x2_t zn) __arm_streaming; svfloat32x4_t svrintp[_f32_x4](svfloat32x4_t zn) __arm_streaming; ``` #### LDR, STR Spill and fill of ZT0 ``` c void svldr_zt(uint64_t zt, const void *rn) __arm_streaming_compatible __arm_inout("zt0"); void svstr_zt(uint64_t zt, void *rn) __arm_streaming_compatible __arm_in("zt0"); ``` #### ZERO Zero ZT0 ``` c void svzero_zt(uint64_t zt) __arm_streaming_compatible __arm_out("zt0"); ``` #### LUTI2, LUTI4 Lookup table read with 2-bit and 4-bit indexes ``` c // Variants are also available for _zt_u8, _zt_s16, _zt_u16, _zt_f16, // _zt_bf16, _zt_s32, _zt_u32 and _zt_f32 svint8_t svluti2_lane_zt_s8(uint64_t zt, svuint8_t zn, uint64_t imm_idx) __arm_streaming __arm_in("zt0"); // Variants are also available for _zt_u8, _zt_s16, _zt_u16, _zt_f16, // _zt_bf16, _zt_s32, _zt_u32 and _zt_f32 svint8x2_t svluti2_lane_zt_s8_x2(uint64_t zt, svuint8_t zn, uint64_t imm_idx) __arm_streaming __arm_in("zt0"); // Variants are also available for _zt_u8, _zt_s16, _zt_u16, _zt_f16, // _zt_bf16, _zt_s32, _zt_u32 and _zt_f32 svint8x4_t svluti2_lane_zt_s8_x4(uint64_t zt, svuint8_t zn, uint64_t imm_idx) __arm_streaming __arm_in("zt0"); // Variants are also available for _zt_u8, _zt_s16, _zt_u16, _zt_f16, // _zt_bf16, _zt_s32, _zt_u32 and _zt_f32 svint8_t svluti4_lane_zt_s8(uint64_t zt, svuint8_t zn, uint64_t imm_idx) __arm_streaming __arm_in("zt0"); // Variants are also available for _zt_u8, _zt_s16, _zt_u16, _zt_f16, // _zt_bf16, _zt_s32, _zt_u32 and _zt_f32 svint8x2_t svluti4_lane_zt_s8_x2(uint64_t zt, svuint8_t zn, uint64_t imm_idx) __arm_streaming __arm_in("zt0"); // Variants are also available for _zt_u16, _zt_f16, _zt_bf16, _zt_s32, // _zt_u32 and _zt_f32 svint16x4_t svluti4_lane_zt_s16_x4(uint64_t zt, svuint8_t zn, uint64_t imm_idx) __arm_streaming __arm_in("zt0"); ``` #### MOVA Move multi-vectors to/from ZA ``` c // Variants are also available for _za8_u8, _za16_s16, _za16_u16, // _za16_f16, _za16_bf16, _za32_s32, _za32_u32, _za32_f32, // _za64_s64, _za64_u64 and _za64_f64 svint8x2_t svread_hor_za8_s8_vg2(uint64_t tile, uint32_t slice) __arm_streaming __arm_in("za"); // Variants are also available for _za8_u8, _za16_s16, _za16_u16, // _za16_f16, _za16_bf16, _za32_s32, _za32_u32, _za32_f32, // _za64_s64, _za64_u64 and _za64_f64 svint8x4_t svread_hor_za8_s8_vg4(uint64_t tile, uint32_t slice) __arm_streaming __arm_in("za"); // Variants are also available for _za8_u8, _za16_s16, _za16_u16, // _za16_f16, _za16_bf16, _za32_s32, _za32_u32, _za32_f32, // _za64_s64, _za64_u64 and _za64_f64 svint8x2_t svread_ver_za8_s8_vg2(uint64_t tile, uint32_t slice) __arm_streaming __arm_in("za"); // Variants are also available for _za8_u8, _za16_s16, _za16_u16, // _za16_f16, _za16_bf16, _za32_s32, _za32_u32, _za32_f32, // _za64_s64, _za64_u64 and _za64_f64 svint8x4_t svread_ver_za8_s8_vg4(uint64_t tile, uint32_t slice) __arm_streaming __arm_in("za"); // Variants are also available for _za8_u8, _za16_s16, _za16_u16, // _za16_f16, _za16_bf16, _za32_s32, _za32_u32, _za32_f32, // _za64_s64, _za64_u64 and _za64_f64 svint8x2_t svread_za8_s8_vg1x2(uint32_t slice) __arm_streaming __arm_in("za"); // Variants are also available for _za8_u8, _za16_s16, _za16_u16, // _za16_f16, _za16_bf16, _za32_s32, _za32_u32, _za32_f32, // _za64_s64, _za64_u64 and _za64_f64 svint8x4_t svread_za8_s8_vg1x4(uint32_t slice) __arm_streaming __arm_in("za"); // Variants are also available for _za8[_u8], _za16[_s16], _za16[_u16], // _za16[_f16], _za16[_bf16], _za32[_s32], _za32[_u32], _za32[_f32], // _za64[_s64], _za64[_u64] and _za64[_f64] void svwrite_hor_za8[_s8]_vg2(uint64_t tile, uint32_t slice, svint8x2_t zn) __arm_streaming __arm_inout("za"); // Variants are also available for _za8[_u8], _za16[_s16], _za16[_u16], // _za16[_f16], _za16[_bf16], _za32[_s32], _za32[_u32], _za32[_f32], // _za64[_s64], _za64[_u64] and _za64[_f64] void svwrite_hor_za8[_s8]_vg4(uint64_t tile, uint32_t slice, svint8x4_t zn) __arm_streaming __arm_inout("za"); // Variants are also available for _za8[_u8], _za16[_s16], _za16[_u16], // _za16[_f16], _za16[_bf16], _za32[_s32], _za32[_u32], _za32[_f32], // _za64[_s64], _za64[_u64] and _za64[_f64] void svwrite_ver_za8[_s8]_vg2(uint64_t tile, uint32_t slice, svint8x2_t zn) __arm_streaming __arm_inout("za"); // Variants are also available for _za8[_u8], _za16[_s16], _za16[_u16], // _za16[_f16], _za16[_bf16], _za32[_s32], _za32[_u32], _za32[_f32], // _za64[_s64], _za64[_u64] and _za64[_f64] void svwrite_ver_za8[_s8]_vg4(uint64_t tile, uint32_t slice, svint8x4_t zn) __arm_streaming __arm_inout("za"); // Variants are also available for _za8[_u8], _za16[_s16], _za16[_u16], // _za16[_f16], _za16[_bf16], _za32[_s32], _za32[_u32], _za32[_f32], // _za64[_s64], _za64[_u64] and _za64[_f64] void svwrite_za8[_s8]_vg1x2(uint32_t slice, svint8x2_t zn) __arm_streaming __arm_inout("za"); // Variants are also available for _za8[_u8], _za16[_s16], _za16[_u16], // _za16[_f16], _za16[_bf16], _za32[_s32], _za32[_u32], _za32[_f32], // _za64[_s64], _za64[_u64] and _za64[_f64] void svwrite_za8[_s8]_vg1x4(uint32_t slice, svint8x4_t zn) __arm_streaming __arm_inout("za"); ``` #### UCLAMP, SCLAMP, FCLAMP Multi-vector clamp to minimum/maximum vector ``` c // Variants are also available for _single_s8_x2, _single_u8_x2, // _single_s16_x2, _single_u16_x2, _single_s32_x2, _single_u32_x2, // _single_f32_x2, _single_s64_x2, _single_u64_x2 and _single_f64_x2 svfloat16x2_t svclamp[_single_f16_x2](svfloat16x2_t zd, svfloat16_t zn, svfloat16_t zm) __arm_streaming; // Variants are also available for _single_s8_x4, _single_u8_x4, // _single_s16_x4, _single_u16_x4, _single_s32_x4, _single_u32_x4, // _single_f32_x4, _single_s64_x4, _single_u64_x4 and _single_f64_x4 svfloat16x4_t svclamp[_single_f16_x4](svfloat16x4_t zd, svfloat16_t zn, svfloat16_t zm) __arm_streaming; ``` #### SEL Multi-vector conditionally select elements from two vectors ``` c // Variants are also available for _s8_x2, _u16_x2, _s16_x2, _f16_x2, // _bf16_x2, _u32_x2, _s32_x2, _f32_x2, _u64_x2, _s64_x2 and _f64_x2 svuint8x2_t svsel[_u8_x2](svcount_t png, svuint8x2_t zn, svuint8x2_t zm) __arm_streaming; // Variants are also available for _s8_x4, _u16_x4, _s16_x4, _f16_x4, // _bf16_x4, _u32_x4, _s32_x4, _f32_x4, _u64_x4, _s64_x4 and _f64_x4 svuint8x4_t svsel[_u8_x4](svcount_t png, svuint8x4_t zn, svuint8x4_t zm) __arm_streaming; ``` #### URSHL, SRSHL (single) Multi-vector rounding shift left ``` c // Variants are also available for _single_u8_x2, _single_u16_x2, // _single_s16_x2, _single_u32_x2, _single_s32_x2, _single_u64_x2 // and _single_s64_x2 svint8x2_t svrshl[_single_s8_x2](svint8x2_t zdn, svint8_t zm) __arm_streaming; // Variants are also available for _single_u8_x4, _single_u16_x4, // _single_s16_x4, _single_u32_x4, _single_s32_x4, _single_u64_x4 // and _single_s64_x4 svint8x4_t svrshl[_single_s8_x4](svint8x4_t zdn, svint8_t zm) __arm_streaming; ``` #### URSHL, SRSHL (multi) Multi-vector rounding shift left ``` c // Variants are also available for _u8_x2, _u16_x2, _s16_x2, _u32_x2, _s32_x2, // _u64_x2 and _s64_x2 svint8x2_t svrshl[_s8_x2](svint8x2_t zdn, svint8x2_t zm) __arm_streaming; // Variants are also available for _u8_x4, _u16_x4, _s16_x4, _u32_x4, _s32_x4, // _u64_x4 and _s64_x4 svint8x4_t svrshl[_s8_x4](svint8x4_t zdn, svint8x4_t zm) __arm_streaming; ``` #### SQRSHR, UQRSHR Multi-vector saturating rounding shift right narrow ``` c // Variants are also available for _u8[_u32_x4] svint8_t svqrshr[_n]_s8[_s32_x4](svint32x4_t zn, uint64_t imm) __arm_streaming; // Variants are also available for _u16[_u32_x2] svint16_t svqrshr[_n]_s16[_s32_x2](svint32x2_t zn, uint64_t imm) __arm_streaming; // Variants are also available for _u16[_u64_x4] svint16_t svqrshr[_n]_s16[_s64_x4](svint64x4_t zn, uint64_t imm) __arm_streaming; ``` #### SQRSHRN, UQRSHRN Multi-vector saturating rounding shift right narrow and interleave ``` c // Variants are also available for _u8[_u32_x4] svint8_t svqrshrn[_n]_s8[_s32_x4](svint32x4_t zn, uint64_t imm) __arm_streaming; // Variants are also available for _u16[_u64_x4] svint16_t svqrshrn[_n]_s16[_s64_x4](svint64x4_t zn, uint64_t imm) __arm_streaming; ``` #### SQRSHRU Multi-vector saturating rounding shift right unsigned narrow ``` c svuint8_t svqrshru[_n]_u8[_s32_x4](svint32x4_t zn, uint64_t imm) __arm_streaming; svuint16_t svqrshru[_n]_u16[_s32_x2](svint32x2_t zn, uint64_t imm) __arm_streaming; svuint16_t svqrshru[_n]_u16[_s64_x4](svint64x4_t zn, uint64_t imm) __arm_streaming; ``` #### SQRSHRUN Multi-vector saturating rounding shift right unsigned narrow and interleave ``` c // Variants are also available for _u16[_s64_x4] svuint8_t svqrshrun[_n]_u8[_s32_x4](svint32x4_t zn, uint64_t imm) __arm_streaming; ``` #### SQDMULH (single) Multi-vector signed saturating doubling multiply high ``` c // Variants are also available for _single_s16_x2, _single_s32_x2 // and _single_s64_x2 svint8x2_t svqdmulh[_single_s8_x2](svint8x2_t zdn, svint8_t zm) __arm_streaming; // Variants are also available for _single_s16_x4, _single_s32_x4 // and _single_s64_x4 svint8x4_t svqdmulh[_single_s8_x4](svint8x4_t zdn, svint8_t zm) __arm_streaming; ``` #### SQDMULH (multi) Multi-vector signed saturating doubling multiply high ``` c // Variants are also available for _s16_x2, _s32_x2 and _s64_x2 svint8x2_t svqdmulh[_s8_x2](svint8x2_t zdn, svint8x2_t zm) __arm_streaming; // Variants are also available for _s16_x4, _s32_x4 and _s64_x4 svint8x4_t svqdmulh[_s8_x4](svint8x4_t zdn, svint8x4_t zm) __arm_streaming; ``` #### SUNPK, UUNPK Multi-vector pack/unpack ``` c // Variants are also available for _u16[_u8_x2], _u32[_u16_x2], _s32[_s16_x2], // _u64[_u32_x2] and _s64[_s32_x2] svint16x2_t svunpk_s16[_s8_x2](svint8_t zn) __arm_streaming; // Variants are also available for _u16[_u8_x4], _u32[_u16_x4], _s32[_s16_x4], // _u64[_u32_x4] and _s64[_s32_x4] svint16x4_t svunpk_s16[_s8_x4](svint8x2_t zn) __arm_streaming; ``` #### ZIP Multi-vector zip. ``` c // Variants are also available for _u8_x2, _u16_x2, _s16_x2, _f16_x2, // _bf16_x2, _u32_x2, _s32_x2, _f32_x2, _u64_x2, _s64_x2 and _f64_x2 svint8x2_t svzip[_s8_x2](svint8x2_t zn) __arm_streaming; // Variants are also available for _u8_x4, _u16_x4, _s16_x4, _f16_x4, // _bf16_x4, _u32_x4, _s32_x4, _f32_x4, _u64_x4, _s64_x4 and _f64_x4 svint8x4_t svzip[_s8_x4](svint8x4_t zn) __arm_streaming; ``` The `svzipq` intrinsics operate on quad-words, but for convenience accept all element types. ``` c // Variants are also available for _u8_x2, _u16_x2, _s16_x2, _f16_x2, // _bf16_x2, _u32_x2, _s32_x2, _f32_x2, _u64_x2, _s64_x2 and _f64_x2 svint8x2_t svzipq[_s8_x2](svint8x2_t zn) __arm_streaming; // Variants are also available for _u8_x4, _u16_x4, _s16_x4, _f16_x4, // _bf16_x4, _u32_x4, _s32_x4, _f32_x4, _u64_x4, _s64_x4 and _f64_x4 svint8x4_t svzipq[_s8_x4](svint8x4_t zn) __arm_streaming; ``` #### UZP Multi-vector unzip. ``` c // Variants are also available for _u8_x2, _u16_x2, _s16_x2, _f16_x2, // _bf16_x2, _u32_x2, _s32_x2, _f32_x2, _u64_x2, _s64_x2 and _f64_x2 svint8x2_t svuzp[_s8_x2](svint8x2_t zn) __arm_streaming; // Variants are also available for _u8_x4, _u16_x4, _s16_x4, _f16_x4, // _bf16_x4, _u32_x4, _s32_x4, _f32_x4, _u64_x4, _s64_x4 and _f64_x4 svint8x4_t svuzp[_s8_x4](svint8x4_t zn) __arm_streaming; ``` The `svuzpq` intrinsics operate on quad-words, but for convenience accept all element types. ``` c // Variants are also available for _u8_x2, _u16_x2, _s16_x2, _f16_x2, // _bf16_x2, _u32_x2, _s32_x2, _f32_x2, _u64_x2, _s64_x2 and _f64_x2 svint8x2_t svuzpq[_s8_x2](svint8x2_t zn) __arm_streaming; // Variants are also available for _u8_x4, _u16_x4, _s16_x4, _f16_x4, // _bf16_x4, _u32_x4, _s32_x4, _f32_x4, _u64_x4, _s64_x4 and _f64_x4 svint8x4_t svuzpq[_s8_x4](svint8x4_t zn) __arm_streaming; ``` ### Streaming-compatible versions of standard routines ACLE provides the following streaming-compatible functions, with the same behavior as the standard C functions that they are named after. All of the functions have external linkage. ``` c void *__arm_sc_memcpy(void *dest, const void *src, size_t n) __arm_streaming_compatible; void *__arm_sc_memmove(void *dest, const void *src, size_t n) __arm_streaming_compatible; void *__arm_sc_memset(void *s, int c, size_t n) __arm_streaming_compatible; void *__arm_sc_memchr(void *s, int c, size_t n) __arm_streaming_compatible; ``` ### SVE2.1 and SME2 instruction intrinsics The functions in this section are defined by either the header file [``](#arm_sve.h) or [``](#arm_sme.h) when `__ARM_FEATURE_SVE2.1` or `__ARM_FEATURE_SME2` is defined, respectively. These intrinsics can only be called from non-streaming code if `__ARM_FEATURE_SVE2p1` is defined. They can only be called from streaming code if the appropriate SME feature macro is defined (see previous paragraph). They can only be called from streaming-compatible code if they could be called from both non-streaming code and streaming code Most function in this section are SME2 or SVE2.1. However some are available in SME. For convinience the ones available in SME will be tagged in the function with `[SME]`. #### UCLAMP, SCLAMP, FCLAMP Clamp to minimum/maximum vector. ``` c // Variants are also available for: // _s8, _u8, _s16, _u16, _s32, _u32 [SME] // _f32, _s64, _u64 and _f64 svfloat16_t svclamp[_f16](svfloat16_t op, svfloat16_t min, svfloat16_t max); ``` #### CNTP Set scalar to count from predicate-as-counter. ``vl`` is expected to be 2 or 4. ``` c // Variants are also available for _c16, _c32 and _c64 uint64_t svcntp_c8(svcount_t pnn, uint64_t vl); ``` #### UDOT, SDOT, FDOT (vectors) Multi-vector dot-product (2-way) ``` c // Variants are also available for _s32_s16 and _u32_u16 svfloat32_t svdot[_f32_f16](svfloat32_t zda, svfloat16_t zn, svfloat16_t zm); ``` #### UDOT, SDOT, FDOT (indexed) Multi-vector dot-product (2-way) ``` c // Variants are also available for _s32_s16 and _u32_u16 svfloat32_t svdot_lane[_f32_f16](svfloat32_t zda, svfloat16_t zn, svfloat16_t zm, uint64_t imm_idx); ``` #### LD1B, LD1D, LD1H, LD1W Contiguous load to multi-vector ``` c // Variants are also available for _s8 svuint8x2_t svld1[_u8]_x2(svcount_t png, const uint8_t *rn); // Variants are also available for _s8 svuint8x4_t svld1[_u8]_x4(svcount_t png, const uint8_t *rn); // Variants are also available for _s8 svuint8x2_t svld1_vnum[_u8]_x2(svcount_t png, const uint8_t *rn, int64_t vnum); // Variants are also available for _s8 svuint8x4_t svld1_vnum[_u8]_x4(svcount_t png, const uint8_t *rn, int64_t vnum); // Variants are also available for _s16, _f16 and _bf16 svuint16x2_t svld1[_u16]_x2(svcount_t png, const uint16_t *rn); // Variants are also available for _s16, _f16 and _bf16 svuint16x4_t svld1[_u16]_x4(svcount_t png, const uint16_t *rn); // Variants are also available for _s16, _f16 and _bf16 svuint16x2_t svld1_vnum[_u16]_x2(svcount_t png, const uint16_t *rn, int64_t vnum); // Variants are also available for _s16, _f16 and _bf16 svuint16x4_t svld1_vnum[_u16]_x4(svcount_t png, const uint16_t *rn, int64_t vnum); // Variants are also available for _s32 and _f32 svuint32x2_t svld1[_u32]_x2(svcount_t png, const uint32_t *rn); // Variants are also available for _s32 and _f32 svuint32x4_t svld1[_u32]_x4(svcount_t png, const uint32_t *rn); // Variants are also available for _s32 and _f32 svuint32x2_t svld1_vnum[_u32]_x2(svcount_t png, const uint32_t *rn, int64_t vnum); // Variants are also available for _s32 and _f32 svuint32x4_t svld1_vnum[_u32]_x4(svcount_t png, const uint32_t *rn, int64_t vnum); // Variants are also available for _s64 and _f64 svuint64x2_t svld1[_u64]_x2(svcount_t png, const uint64_t *rn); // Variants are also available for _s64 and _f64 svuint64x4_t svld1[_u64]_x4(svcount_t png, const uint64_t *rn); // Variants are also available for _s64 and _f64 svuint64x2_t svld1_vnum[_u64]_x2(svcount_t png, const uint64_t *rn, int64_t vnum); // Variants are also available for _s64 and _f64 svuint64x4_t svld1_vnum[_u64]_x4(svcount_t png, const uint64_t *rn, int64_t vnum); ``` #### LDNT1B, LDNT1D, LDNT1H, LDNT1W Contiguous non-temporal load to multi-vector ``` c // Variants are also available for _s8 svuint8x2_t svldnt1[_u8]_x2(svcount_t png, const uint8_t *rn); // Variants are also available for _s8 svuint8x4_t svldnt1[_u8]_x4(svcount_t png, const uint8_t *rn); // Variants are also available for _s8 svuint8x2_t svldnt1_vnum[_u8]_x2(svcount_t png, const uint8_t *rn, int64_t vnum); // Variants are also available for _s8 svuint8x4_t svldnt1_vnum[_u8]_x4(svcount_t png, const uint8_t *rn, int64_t vnum); // Variants are also available for _s16, _f16 and _bf16 svuint16x2_t svldnt1[_u16]_x2(svcount_t png, const uint16_t *rn); // Variants are also available for _s16, _f16 and _bf16 svuint16x4_t svldnt1[_u16]_x4(svcount_t png, const uint16_t *rn); // Variants are also available for _s16, _f16 and _bf16 svuint16x2_t svldnt1_vnum[_u16]_x2(svcount_t png, const uint16_t *rn, int64_t vnum); // Variants are also available for _s16, _f16 and _bf16 svuint16x4_t svldnt1_vnum[_u16]_x4(svcount_t png, const uint16_t *rn, int64_t vnum); // Variants are also available for _s32 and _f32 svuint32x2_t svldnt1[_u32]_x2(svcount_t png, const uint32_t *rn); // Variants are also available for _s32 and _f32 svuint32x4_t svldnt1[_u32]_x4(svcount_t png, const uint32_t *rn); // Variants are also available for _s32 and _f32 svuint32x2_t svldnt1_vnum[_u32]_x2(svcount_t png, const uint32_t *rn, int64_t vnum); // Variants are also available for _s32 and _f32 svuint32x4_t svldnt1_vnum[_u32]_x4(svcount_t png, const uint32_t *rn, int64_t vnum); // Variants are also available for _s64 and _f64 svuint64x2_t svldnt1[_u64]_x2(svcount_t png, const uint64_t *rn); // Variants are also available for _s64 and _f64 svuint64x4_t svldnt1[_u64]_x4(svcount_t png, const uint64_t *rn); // Variants are also available for _s64 and _f64 svuint64x2_t svldnt1_vnum[_u64]_x2(svcount_t png, const uint64_t *rn, int64_t vnum); // Variants are also available for _s64 and _f64 svuint64x4_t svldnt1_vnum[_u64]_x4(svcount_t png, const uint64_t *rn, int64_t vnum); ``` #### BFMLSLB, BFMLSLT BFloat16 floating-point multiply-subtract long from single-precision (top/bottom) ``` c svfloat32_t svbfmlslb[_f32](svfloat32_t zda, svbfloat16_t zn, svbfloat16_t zm); svfloat32_t svbfmlslb_lane[_f32](svfloat32_t zda, svbfloat16_t zn, svbfloat16_t zm, uint64_t imm_idx); svfloat32_t svbfmlslt[_f32](svfloat32_t zda, svbfloat16_t zn, svbfloat16_t zm); svfloat32_t svbfmlslt_lane[_f32](svfloat32_t zda, svbfloat16_t zn, svbfloat16_t zm, uint64_t imm_idx); ``` #### PEXT Transform a predicate-as-counter to a predicate (pair). ``` c // Variants are also available for _c16, _c32 and _c64 svbool_t svpext_lane_c8(svcount_t pnn, uint64_t imm); // Variants are also available for _c16, _c32 and _c64 svboolx2_t svpext_lane_c8_x2(svcount_t pnn, uint64_t imm); ``` #### PSEL Predicate select between predicate value or all-false ``` c // Variants are also available for _b16, _b32 and _b64 [SME] svbool_t svpsel_lane_b8(svbool_t pn, svbool_t pm, uint32_t idx); // Variants are also available for _c16, _c32 and _c64 svcount_t svpsel_lane_c8(svcount_t pn, svbool_t pm, uint32_t idx); ``` #### PTRUE, PFALSE Initialise predicate-as-counter to all active or all inactive. ``` c // Variants are also available for _c16, _c32 and _c64 svcount_t svptrue_c8(); svcount_t svpfalse_c(void); ``` #### REVD Reverse doublewords in elements. ``` c // All the intrinsics below are [SME] // Variants are available for: // _s8, _s16, _u16, _s32, _u32, _s64, _u64 // _bf16, _f16, _f32, _f64 svuint8_t svrevd[_u8]_m(svuint8_t zd, svbool_t pg, svuint8_t zn); // Variants are available for: // _s8, _s16, _u16, _s32, _u32, _s64, _u64 // _bf16, _f16, _f32, _f64 svuint8_t svrevd[_u8]_z(svbool_t pg, svuint8_t zn); // Variants are available for: // _s8, _s16, _u16, _s32, _u32, _s64, _u64 // _bf16, _f16, _f32, _f64 svuint8_t svrevd[_u8]_x(svbool_t pg, svuint8_t zn); ``` #### SQCVTN, SQCVTUN, UQCVTN Multi-vector saturating extract narrow and interleave ``` c // Variants are also available for _u16[_s32_x2] and _u16[_u32_x2] svint16_t svqcvtn_s16[_s32_x2](svint32x2_t zn); ``` #### SQRSHRN, UQRSHRN Multi-vector saturating rounding shift right narrow and interleave ``` c // Variants are also available for _u16[_u32_x2] svint16_t svqrshrn[_n]_s16[_s32_x2](svint32x2_t zn, uint64_t imm); ``` #### SQRSHRUN Multi-vector saturating rounding shift right unsigned narrow and interleave ``` c svuint16_t svqrshrun[_n]_u16[_s32_x2](svint32x2_t zn, uint64_t imm); ``` #### ST1B, ST1D, ST1H, ST1W Contiguous store of multi-vector operand ``` c // Variants are also available for _s8_x2 void svst1[_u8_x2](svcount_t png, uint8_t *rn, svuint8x2_t zt); // Variants are also available for _s8_x4 void svst1[_u8_x4](svcount_t png, uint8_t *rn, svuint8x4_t zt); // Variants are also available for _s8_x2 void svst1_vnum[_u8_x2](svcount_t png, uint8_t *rn, int64_t vnum, svuint8x2_t zt); // Variants are also available for _s8_x4 void svst1_vnum[_u8_x4](svcount_t png, uint8_t *rn, int64_t vnum, svuint8x4_t zt); // Variants are also available for _s16_x2, _f16_x2 and _bf16_x2 void svst1[_u16_x2](svcount_t png, uint16_t *rn, svuint16x2_t zt); // Variants are also available for _s16_x4, _f16_x4 and _bf16_x4 void svst1[_u16_x4](svcount_t png, uint16_t *rn, svuint16x4_t zt); // Variants are also available for _s16_x2, _f16_x2 and _bf16_x2 void svst1_vnum[_u16_x2](svcount_t png, uint16_t *rn, int64_t vnum, svuint16x2_t zt); // Variants are also available for _s16_x4, _f16_x4 and _bf16_x4 void svst1_vnum[_u16_x4](svcount_t png, uint16_t *rn, int64_t vnum, svuint16x4_t zt); // Variants are also available for _s32_x2 and _f32_x2 void svst1[_u32_x2](svcount_t png, uint32_t *rn, svuint32x2_t zt); // Variants are also available for _s32_x4 and _f32_x4 void svst1[_u32_x4](svcount_t png, uint32_t *rn, svuint32x4_t zt); // Variants are also available for _s32_x2 and _f32_x2 void svst1_vnum[_u32_x2](svcount_t png, uint32_t *rn, int64_t vnum, svuint32x2_t zt); // Variants are also available for _s32_x4 and _f32_x4 void svst1_vnum[_u32_x4](svcount_t png, uint32_t *rn, int64_t vnum, svuint32x4_t zt); // Variants are also available for _s64_x2 and _f64_x2 void svst1[_u64_x2](svcount_t png, uint64_t *rn, svuint64x2_t zt); // Variants are also available for _s64_x4 and _f64_x4 void svst1[_u64_x4](svcount_t png, uint64_t *rn, svuint64x4_t zt); // Variants are also available for _s64_x2 and _f64_x2 void svst1_vnum[_u64_x2](svcount_t png, uint64_t *rn, int64_t vnum, svuint64x2_t zt); // Variants are also available for _s64_x4 and _f64_x4 void svst1_vnum[_u64_x4](svcount_t png, uint64_t *rn, int64_t vnum, svuint64x4_t zt); ``` #### STNT1B, STNT1D, STNT1H, STNT1W Contiguous non-temporal store of multi-vector operand ``` c // Variants are also available for _s8_x2 void svstnt1[_u8_x2](svcount_t png, uint8_t *rn, svuint8x2_t zt); // Variants are also available for _s8_x4 void svstnt1[_u8_x4](svcount_t png, uint8_t *rn, svuint8x4_t zt); // Variants are also available for _s8_x2 void svstnt1_vnum[_u8_x2](svcount_t png, uint8_t *rn, int64_t vnum, svuint8x2_t zt); // Variants are also available for _s8_x4 void svstnt1_vnum[_u8_x4](svcount_t png, uint8_t *rn, int64_t vnum, svuint8x4_t zt); // Variants are also available for _s16_x2, _f16_x2 and _bf16_x2 void svstnt1[_u16_x2](svcount_t png, uint16_t *rn, svuint16x2_t zt); // Variants are also available for _s16_x4, _f16_x4 and _bf16_x4 void svstnt1[_u16_x4](svcount_t png, uint16_t *rn, svuint16x4_t zt); // Variants are also available for _s16_x2, _f16_x2 and _bf16_x2 void svstnt1_vnum[_u16_x2](svcount_t png, uint16_t *rn, int64_t vnum, svuint16x2_t zt); // Variants are also available for _s16_x4, _f16_x4 and _bf16_x4 void svstnt1_vnum[_u16_x4](svcount_t png, uint16_t *rn, int64_t vnum, svuint16x4_t zt); // Variants are also available for _s32_x2 and _f32_x2 void svstnt1[_u32_x2](svcount_t png, uint32_t *rn, svuint32x2_t zt); // Variants are also available for _s32_x4 and _f32_x4 void svstnt1[_u32_x4](svcount_t png, uint32_t *rn, svuint32x4_t zt); // Variants are also available for _s32_x2 and _f32_x2 void svstnt1_vnum[_u32_x2](svcount_t png, uint32_t *rn, int64_t vnum, svuint32x2_t zt); // Variants are also available for _s32_x4 and _f32_x4 void svstnt1_vnum[_u32_x4](svcount_t png, uint32_t *rn, int64_t vnum, svuint32x4_t zt); // Variants are also available for _s64_x2 and _f64_x2 void svstnt1[_u64_x2](svcount_t png, uint64_t *rn, svuint64x2_t zt); // Variants are also available for _s64_x4 and _f64_x4 void svstnt1[_u64_x4](svcount_t png, uint64_t *rn, svuint64x4_t zt); // Variants are also available for _s64_x2 and _f64_x2 void svstnt1_vnum[_u64_x2](svcount_t png, uint64_t *rn, int64_t vnum, svuint64x2_t zt); // Variants are also available for _s64_x4 and _f64_x4 void svstnt1_vnum[_u64_x4](svcount_t png, uint64_t *rn, int64_t vnum, svuint64x4_t zt); ``` #### WHILEGE, WHILEGT, WHILEHI, WHILEHS, WHILELE, WHILELO, WHILELS, WHILELT While (resulting in predicate-as-counter). ``vl`` is expected to be 2 or 4. ``` c // Variants are also available for _c16[_s64], _c32[_s64] _c64[_s64], // _c8[_u64], _c16[_u64], _c32[_u64] and _c64[_u64] svcount_t svwhilege_c8[_s64](int64_t rn, int64_t rm, uint64_t vl); // Variants are also available for _c16[_s64], _c32[_s64] _c64[_s64], // _c8[_u64], _c16[_u64], _c32[_u64] and _c64[_u64] svcount_t svwhilegt_c8[_s64](int64_t rn, int64_t rm, uint64_t vl); // Variants are also available for _c16[_s64], _c32[_s64] _c64[_s64], // _c8[_u64], _c16[_u64], _c32[_u64] and _c64[_u64] svcount_t svwhilele_c8[_s64](int64_t rn, int64_t rm, uint64_t vl); // Variants are also available for _c16[_s64], _c32[_s64] _c64[_s64], // _c8[_u64], _c16[_u64], _c32[_u64] and _c64[_u64] svcount_t svwhilelt_c8[_s64](int64_t rn, int64_t rm, uint64_t vl); ``` While (resulting in predicate tuple) ``` c // Variants are also available for _b16[_s64]_x2, _b32[_s64]_x2, // _b64[_s64]_x2, _b8[_u64]_x2, _b16[_u64]_x2, _b32[_u64]_x2 and // _b64[_u64]_x2 svboolx2_t svwhilege_b8[_s64]_x2(int64_t rn, int64_t rm); // Variants are also available for _b16[_s64]_x2, _b32[_s64]_x2, // _b64[_s64]_x2, _b8[_u64]_x2, _b16[_u64]_x2, _b32[_u64]_x2 and // _b64[_u64]_x2 svboolx2_t svwhilegt_b8[_s64]_x2(int64_t rn, int64_t rm); // Variants are also available for _b16[_s64]_x2, _b32[_s64]_x2, // _b64[_s64]_x2, _b8[_u64]_x2, _b16[_u64]_x2, _b32[_u64]_x2 and // _b64[_u64]_x2 svboolx2_t svwhilele_b8[_s64]_x2(int64_t rn, int64_t rm); // Variants are also available for _b16[_s64]_x2, _b32[_s64]_x2, // _b64[_s64]_x2, _b8[_u64]_x2, _b16[_u64]_x2, _b32[_u64]_x2 and // _b64[_u64]_x2 svboolx2_t svwhilelt_b8[_s64]_x2(int64_t rn, int64_t rm); ``` # M-profile Vector Extension (MVE) intrinsics The M-profile Vector Extension (MVE) [[MVE-spec]](#MVE-spec) instructions provide packed Single Instruction Multiple Data (SIMD) and single-element scalar operations on a range of integer and floating-point types. MVE can also be referred to as Helium. The M-profile Vector Extension provides for arithmetic, logical and saturated arithmetic operations on 8-bit, 16-bit and 32-bit integers (and sometimes on 64-bit integers) and on 16-bit and 32-bit floating-point data, arranged in 128-bit vectors. The intrinsics in this section provide C and C++ programmers with a simple programming model allowing easy access to the code generation of the MVE instructions for the Armv8.1-M Mainline architecture. ## Concepts The MVE instructions are designed to improve the performance of SIMD operations by operating on 128-bit *vectors* of *elements* of the same *scalar* data type. For example, `uint16x8_t` is a 128-bit vector type consisting of eight elements of the scalar `uint16_t` data type. Likewise, `uint8x16_t` is a 128-bit vector type consisting of sixteen `uint8_t` elements. In a vector programming model, operations are performed in parallel across the elements of the vector. For example, `vmulq_u16(a, b)` is a vector intrinsic which takes two `uint16x8_t` vector arguments `a` and `b`, and returns the result of multiplying corresponding elements from each vector together. The M-profile Vector Extension also provides support for *vector-by-scalar* operations. In these operations, a scalar value is provided directly, duplicated to create a new vector with the same number of elements as an input vector, and an operation is performed in parallel between this new vector and other input vectors. For example, `vaddq_n_u16(a, s)`, is a vector-by-scalar intrinsic which takes one `uint16x8_t` vector argument and one `uint16_t` scalar argument. A new vector is formed which consists of eight copies of `s`, and this new vector is multiplied by `a`. *Reductions* work across the whole of a single vector performing the same operation between elements of that vector. For example, `vaddvq_u16(a)` is a reduction intrinsic which takes a `uint16x8_t` vector, adds each of the eight `uint16_t` elements together, and returns a `uint32_t` result containing the sum. Note the difference in return types between MVE's `vaddvq_u16` and Advanced SIMD's implementation of the same name intrinsic, MVE returns the `uint32_t` type whereas Advanced SIMD returns the element type `uint16_t`. *Cross-lane* and *pairwise* vector operations work on pairs of elements within a vector, sometimes performing the same operation like in the case of the vector saturating doubling multiply subtract dual returning high half with exchange `vqdmlsdhxq_s8` or sometimes a different one as is the case with the vector complex addition intrinsic `vcaddq_rot90_s8`. Some intrinsics may only read part of the input vectors whereas others may only write part of the results. For example, the vector multiply long intrinsics, depending on whether you use `vmullbq_int_s32` or `vmulltq_int_s32`, will read the even (bottom) or odd (top) elements of each `int16x8_t` input vectors, multiply them and write to a double-width `int32x4_t` vector. In contrast the vector shift right and narrow will read in a double-width input vector and, depending on whether you pick the bottom or top variant, write to the even or odd elements of the single-width result vector. For example, `vshrnbq_n_s16(a, b, 2)` will take each eight elements of type `int16_t` of argument `b`, shift them right by two, narrow them to eight bits and write them to the even elements of the `int8x16_t` result vector, where the odd elements are picked from the equally typed `int8x16_t` argument `a`. *Predication*: the M-profile Vector Extension uses vector predication to allow SIMD operations on selected lanes. The MVE intrinsics expose vector predication by providing predicated intrinsic variants for instructions that support it. These intrinsics can be recognized by one of the four suffixes: * `_m` (merging) which indicates that false-predicated lanes are not written to and keep the same value as they had in the first argument of the intrinsic. * `_p` (predicated) which indicates that false-predicated lanes are not used in the SIMD operation. For example `vaddvq_p_s8`, where the false-predicated lanes are not added to the resulting sum. * `_z` (zero) which indicates that false-predicated lanes are filled with zeroes. These are only used for load instructions. * `_x` (dont-care) which indicates that the false-predicated lanes have undefined values. These are syntactic sugar for merge intrinsics with a `vuninitializedq` inactive parameter. These predicated intrinsics can also be recognized by their last parameter being of type `mve_pred16_t`. This is an alias for the `uint16_t` type. Some predicated intrinsics may have a dedicated first parameter to specify the value in the result vector for the false-predicated lanes; this argument will be of the same type as the result type. For example, `v = veorq_m_s8(inactive, a, b, p)`, will write to each of the sixteen lanes of the result vector `v`, either the result of the exclusive or between the corresponding lanes of vectors `a` and `b`, or the corresponding lane of vector `inactive`, depending on whether that lane is true- or false-predicated in `p`. The types of `inactive`, `a`, `b` and `v` are all `int8x16_t` in this case and `p` has type `mve_pred16_t`. When calling a predicated intrinsic, the predicate mask value should contain the same value in all bits corresponding to the same element of an input or output vector. For example, an instruction operating on 32-bit vector elements should have a predicate mask in which each block of 4 bits is either all 0 or all 1. ``` c mve_pred16_t mask8 = vcmpeqq_u8 (a, b); uint8x16_t r8 = vaddq_m_u8 (inactive, a, b, mask8); // OK uint16x8_t r16 = vaddq_m_u16 (inactive, c, d, mask8); // UNDEFINED BEHAVIOR mve_pred16_t mask8 = 0x5555; // Predicate every other byte. uint8x16_t r8 = vaddq_m_u8 (inactive, a, b, mask8); // OK uint16x8_t r16 = vaddq_m_u16 (inactive, c, d, mask8); // UNDEFINED BEHAVIOR ``` In cases where the input and output vectors have different sizes (a widening or narrowing operation), the mask should be consistent with the largest element size used by the intrinsic. For example, `vcvtbq_m_f16_f32` and `vcvtbq_m_f32_f16` should *both* be passed a predicate mask consistent with 32-bit vector lanes. Users wishing to exploit the MVE architecture's predication behavior in finer detail than this constraint permits are encouraged to use inline assembly. ## Scalar shift intrinsics The M-profile Vector Extension (MVE) also provides a set of scalar shift instructions that operate on signed and unsigned double-words and single-words. These shifts can perform additional saturation, rounding, or both. The ACLE for MVE defines intrinsics for these instructions. ## Namespace By default all M-profile Vector Extension intrinsics are available with and without the `__arm_` prefix. If the `__ARM_MVE_PRESERVE_USER_NAMESPACE` macro is defined, the `__arm_` prefix is mandatory. This is available to hide the user-namespace-polluting variants of the intrinsics. ## Intrinsic polymorphism The ACLE for the M-profile Vector Extension intrinsics was designed in such a way that it supports a polymorphic implementation of most intrinsics. The polymorphic name of an intrinsic is indicated by leaving out the type suffix enclosed in square brackets, for example the vector addition intrinsic `vaddq[_s32]` can be called using the function name `vaddq`. Note that the polymorphism is only possible on input parameter types and intrinsics with the same name must still have the same number of parameters. This is expected to aid implementation of the polymorphism using C11's `_Generic` selection. ## Vector data types Vector data types are named as a lane type and a multiple. Lane type names are based on the types defined in ``. For example,. `int16x8_t` is a vector of eight `int16_t` values. The base types are `int8_t`, `uint8_t`, `int16_t`, `uint16_t`, `int32_t`, `uint32_t`, `int64_t`, `uint64_t`, `float16_t` and `float32_t`. The multiples are such that the resulting vector types are 128-bit. ## Vector array data types Array types are defined for multiples of 2 and 4 of all the vector types, for use in load and store operations. For a vector type `_t` the corresponding array type is `x_t`. Concretely, an array type is a structure containing a single array element called `val`. For example, an array of two `int16x8_t` types is `int16x4x8_t`, and is represented as ``` c struct int16x8x2_t { int16x8_t val[2]; }; ``` ## Scalar data types For consistency, `` defines some additional scalar data types to match the vector types. `float32_t` is defined as an alias for `float`, `float16_t` is defined as an alias for `__fp16` and `mve_pred16_t` is defined as an alias for `uint16_t`. ## Operations on data types ACLE does not define implicit conversion between different data types. E.g. ``` c int32x4_t x; uint32x4_t y = x; // No representation change float32x4_t z = x; // Conversion of integer to floating type ``` Is not portable. Use the `vreinterpretq` intrinsics to convert from one vector type to another without changing representation, and use the `vcvtq` intrinsics to convert between integer and floating types; for example: ``` c int32x4_t x; uint32x4_t y = vreinterpretq_u32_s32(x); float32x4_t z = vcvtq_f32_s32(x); ``` ACLE does not define static construction of vector types. E.g. ``` c int32x4_t x = { 1, 2, 3, 4 }; ``` Is not portable. Use the `vcreateq` or `vdupq` intrinsics to construct values from scalars. In C++, ACLE does not define whether MVE data types are POD types or whether they can be inherited from. ## Compatibility with other vector programming models ACLE does not specify how the MVE Intrinsics interoperate with alternative vector programming models. Consequently, programmers should take particular care when combining the MVE programming model with such programming models. For example, the GCC vector extensions permit initialising a variable using array syntax, as so ``` c #include "arm_mve.h" ... uint32x4_t x = {0, 1, 2, 3}; // GCC extension. uint32_t y = vgetq_lane_s32 (x, 0); // ACLE MVE Intrinsic. ``` But the definition of the GCC vector extensions is such that the value stored in `y` will depend on whether the program is running in big- or little-endian mode. It is recommended that MVE Intrinsics be used consistently: ``` c #include "arm_mve.h" ... const int temp[4] = {0, 1, 2, 3}; uint32x4_t x = vld1q_s32 (temp); uint32_t y = vgetq_lane_s32 (x, 0); ``` ## Availability of M-profile Vector Extension intrinsics M-profile Vector Extension support is available if the `__ARM_FEATURE_MVE` macro has a value other than 0 (see [M-profile Vector Extension](#m-profile-vector-extension)). The availability of the MVE Floating Point data types and intrinsics are predicated on the value of this macro having bit two set. In order to access the MVE intrinsics, it is necessary to include the `` header. ``` c #if (__ARM_FEATURE_MVE & 3) == 3 #include /* MVE integer and floating point intrinsics are now available to use. */ #elif __ARM_FEATURE_MVE & 1 #include /* MVE integer intrinsics are now available to use. */ #endif ``` ### Specification of M-profile Vector Extension intrinsics The M-profile Vector Extension intrinsics are specified in the Arm MVE Intrinsics Reference Architecture Specification [[MVE]](#MVE). The behavior of an intrinsic is specified to be equivalent to the MVE instruction it is mapped to in [[MVE]](#MVE). Intrinsics are specified as a mapping between their name, arguments and return values and the MVE instruction and assembler operands which they are equivalent to. A compiler may make use of the as-if rule from C [[C99]](#C99) (5.1.2.3) to perform optimizations which preserve the instruction semantics. ### Undefined behavior Care should be taken by compiler implementers not to introduce the concept of undefined behavior to the semantics of an intrinsic. ### Alignment assertions The MVE load and store instructions provide for alignment assertions, which may speed up access to aligned data (and will fault access to unaligned data). The MVE intrinsics do not directly provide a means for asserting alignment. # Transactional Memory Extension (TME) intrinsics ## Introduction This section describes the intrinsics for the instructions of the Transactional Memory Extension (TME). TME adds support for transactional execution where transactions are started and committed by a set of new instructions. The TME instructions are present in the AArch64 execution state only. TME is designed to improve performance in cases where larger system scaling requires atomic and isolated access to data structures whose composition is dynamic in nature and therefore not readily amenable to fine-grained locking or lock-free approaches. TME transactions are *isolated*. This means that transactional stores are hidden from other observers, and transactional loads cannot see stores from other observers until the transaction commits. Also, if the transaction fails then stores to memory and writes to registers by the transaction are discarded and the processor returns to the state it had when the transaction started. TME transactions are *best-effort*. This means that the architecture does not guarantee success for any transaction. The architecture requires that all transactions specify a failure handler allowing the software to fallback to a non-transactional alternative to provide guarantees of forward progress. TME defines *flattened nesting* of transactions, where nested transactions are subsumed by the outer transaction. This means that the effects of a nested transaction do not become visible to other observers until the outer transaction commits. When a nested transaction fails it causes the outer transaction, and all nested transactions within, to fail. The TME intrinsics are available when `__ARM_FEATURE_TME` is defined. ## Failure definitions Transactions can fail due to various causes. The following macros are defined to help use or detect these causes. ``` c #define _TMFAILURE_REASON 0x00007fffu #define _TMFAILURE_RTRY 0x00008000u #define _TMFAILURE_CNCL 0x00010000u #define _TMFAILURE_MEM 0x00020000u #define _TMFAILURE_IMP 0x00040000u #define _TMFAILURE_ERR 0x00080000u #define _TMFAILURE_SIZE 0x00100000u #define _TMFAILURE_NEST 0x00200000u #define _TMFAILURE_DBG 0x00400000u #define _TMFAILURE_INT 0x00800000u #define _TMFAILURE_TRIVIAL 0x01000000u ``` ## Intrinsics ``` c uint64_t __tstart (void); ``` Starts a new transaction. When the transaction starts successfully the return value is 0. If the transaction fails, all state modifications are discarded and a cause of the failure is encoded in the return value. The macros defined in [Failure definitions](#failure-definitions) can be used to detect the cause of the failure. ``` c void __tcommit (void); ``` Commits the current transaction. For a nested transaction, the only effect is that the transactional nesting depth is decreased. For an outer transaction, the state modifications performed transactionally are committed to the architectural state. ``` c void __tcancel (/*constant*/ uint64_t); ``` Cancels the current transaction and discards all state modifications that were performed transactionally. The intrinsic takes a 16-bit immediate input that encodes the cancellation reason. This input could be given as ``` c __tcancel (_TMFAILURE_RTRY | (failure_reason & _TMFAILURE_REASON)); ``` if retry is true or ``` c __tcancel (failure_reason & _TMFAILURE_REASON); ``` if retry is false. ``` c uint64_t __ttest (void); ``` Tests if executing inside a transaction. If no transaction is currently executing, the return value is 0. Otherwise, this intrinsic returns the depth of the transaction. ## Instructions | **Intrinsics** | **Argument** | **Result** | **Instruction** | | --------------------------------------------- | ---------------- | -------------- | ----------------- | | uint64_t __tstart (void) | - | Xt -> result | tstart | | void __tcommit (void) | - | - | tcommit | | void __tcancel (/*constant*/ uint64_t reason) | reason -> # | - | tcancel # | | uint64_t __ttest (void) | - | Xt -> result | ttest | These intrinsics are available when `arm_acle.h` is included. # memcpy family of operations intrinsics - MOPS ## Introduction This section describes the intrinsic for the new instructions introduced in the Armv8.8-A and Armv9.3-A architecture updates for the `memcpy`, `memmove` and `memset` family of memory operations (MOPS). These instructions are designed to enable the standardization of the software implementation of those operations. Therefore, most of the use cases for the new instructions are covered by the compiler's code generation or by library implementations. An exception to that is the set of instructions covering the `memset` operation with memory tagging. An intrinsic is available to provide access to this operation. See [Memory tagging](#memory-tagging) for more information on memory tagging. Note: the `` header should be included before using this intrinsic. This intrinsic is available when both `__ARM_FEATURE_MOPS` and `__ARM_FEATURE_MEMORY_TAGGING` are defined. ``` c void* __arm_mops_memset_tag(void* tagged_address, int value, size_t size) ``` This intrinsic performs a `memset` operation with tag setting on a memory block. The parameters of `__arm_mops_memset_tag` are as follows: * `tagged_address`: destination address to be set, containing the allocation tag in its bits `[59:56]`. The address should be aligned with the tag granule size. (See the [SETG\* instructions specification](`](#arm_neon_sve_bridge.h) header should be included before using these intrinsics. ### `svset_neonq` These intrinsics set the first 128 bits of SVE vector `vec` to `subvec`. That is, bit *i* of the result is equal to: * bit *i* of `subvec` if *i* < 128 * bit *i* of `vec` otherwise On big-endian targets, this leaves lanes in a different order from the “native” SVE order. For example, if `subvec` is `int32x4_t`, then on big-endian targets, the first memory element is in lane 3 of `subvec` and is therefore in lane 3 of the returned SVE vector. Using `svld1` to load elements would instead put the first memory element in lane 0 of the returned SVE vector. When `svundef` is passed as the `vec` parameter, compilers are able to reuse the SVE register overlapping the NEON input without generating additional instructions. | **Instances** | |--------------------------------------------------------------------------| | `svint8_t svset_neonq[_s8](svint8_t vec, int8x16_t subvec)` | | `svint16_t svset_neonq[_s16](svint16_t vec, int16x8_t subvec)` | | `svint32_t svset_neonq[_s32](svint32_t vec, int32x4_t subvec)` | | `svint64_t svset_neonq[_s64](svint64_t vec, int64x2_t subvec)` | | `svuint8_t svset_neonq[_u8](svuint8_t vec, uint8x16_t subvec)` | | `svuint16_t svset_neonq[_u16](svuint16_t vec, uint16x8_t subvec)` | | `svuint32_t svset_neonq[_u32](svuint32_t vec, uint32x4_t subvec)` | | `svuint64_t svset_neonq[_u64](svuint64_t vec, uint64x2_t subvec)` | | `svfloat16_t svset_neonq[_f16](svfloat16_t vec, float16x8_t subvec)` | | `svfloat32_t svset_neonq[_f32](svfloat32_t vec, float32x4_t subvec)` | | `svfloat64_t svset_neonq[_f64](svfloat64_t vec, float64x2_t subvec)` | | `svbfloat16_t svset_neonq[_bf16](svbfloat16_t vec, bfloat16x8_t subvec)` | ### `svget_neonq` These intrinsics get the first 128 bit subvector of SVE vector `vec` as a NEON vector. | **Instances** | |-----------------------------------------------------| | `int8x16_t svget_neonq[_s8](svint8_t vec)` | | `int16x8_t svget_neonq[_s16](svint16_t vec)` | | `int32x4_t svget_neonq[_s32](svint32_t vec)` | | `int64x2_t svget_neonq[_s64](svint64_t vec)` | | `uint8x16_t svget_neonq[_u8](svuint8_t vec)` | | `uint16x8_t svget_neonq[_u16](svuint16_t vec)` | | `uint32x4_t svget_neonq[_u32](svuint32_t vec)` | | `uint64x2_t svget_neonq[_u64](svuint64_t vec)` | | `float16x8_t svget_neonq[_f16](svfloat16_t vec)` | | `float32x4_t svget_neonq[_f32](svfloat32_t vec)` | | `float64x2_t svget_neonq[_f64](svfloat64_t vec)` | | `bfloat16x8_t svget_neonq[_bf16](svbfloat16_t vec)` | ### `svdup_neonq` These intrinsics return an SVE vector with all SVE subvectors containing the duplicated NEON vector `vec`. | **Instances** | |-----------------------------------------------------| | `svint8_t svdup_neonq[_s8](int8x16_t vec)` | | `svint16_t svdup_neonq[_s16](int16x8_t vec)` | | `svint32_t svdup_neonq[_s32](int32x4_t vec)` | | `svint64_t svdup_neonq[_s64](int64x2_t vec)` | | `svuint8_t svdup_neonq[_u8](uint8x16_t vec)` | | `svuint16_t svdup_neonq[_u16](uint16x8_t vec)` | | `svuint32_t svdup_neonq[_u32](uint32x4_t vec)` | | `svuint64_t svdup_neonq[_u64](uint64x2_t vec)` | | `svfloat16_t svdup_neonq[_f16](float16x8_t vec)` | | `svfloat32_t svdup_neonq[_f32](float32x4_t vec)` | | `svfloat64_t svdup_neonq[_f64](float64x2_t vec)` | | `svbfloat16_t svdup_neonq[_bf16](bfloat16x8_t vec)` | # Future directions ## Extensions under consideration ### Procedure calls and the Q / GE bits The Arm procedure call standard [[AAPCS]](#AAPCS) states that the Q and GE bits are undefined across public interfaces, but in practice it is desirable to return saturation status from functions. There are at least two common use cases: To define small (inline) functions (defined in terms of expressions involving intrinsics, which provide abstractions or emulate other intrinsic families), it is desirable for such functions to have the same well-defined effects on the Q/GE bits as the corresponding intrinsics. ### DSP library functions Options being considered are to define an extension to the pcs attribute to indicate that Q is meaningful on the return, and possibly also to infer this in the case of functions marked as inline. ### Returning a value in registers As a type attribute this would allow things like ``` c struct __attribute__((value_in_regs)) Point { int x[2]; }; ``` This would indicate that the result registers should be used as if the type had been passed as the first argument. The implementation should not complain if the attribute is applied inappropriately (i.e. where insufficient registers are available) it might be a template instance. ### Custom calling conventions Some interfaces may use calling conventions that depart from the AAPCS. Examples include: * Using additional argument registers, for example passing an argument in R5, R7, R12. * Using additional result registers, for example R0 and R1 for a combined divide-and-remainder routine (note that some implementations may be able to support this by means of a value in registers structure return). * Returning results in the condition flags. * Preserving and possibly setting the Q (saturation) bit. ### Traps: system calls, breakpoints, ... This release of ACLE does not define how to invoke a SVC (supervisor call), BKPT (breakpoint) and other related functionality. One option would be to mark a function prototype with an attribute, for example ``` c int __attribute__((svc(0xAB))) system_call(int code, void const *params); ``` When calling the function, arguments and results would be marshalled according to the AAPCS, the only difference being that the call would be invoked as a trap instruction rather than a branch-and-link. One issue is that some calls may have non-standard calling conventions. (For example, Arm Linux system calls expect the code number to be passed in R7.) Another issue is that the code may vary between A32 and T32 state. This issue could be addressed by allowing two numeric parameters in the attribute. ### Mixed-endian data Extensions for accessing data in different endianness have been considered. However, this is not an issue specific to the Arm architecture, and it seems better to wait for a lead from language standards. ### Memory access with non-temporal hints Supporting memory access with cacheability hints through language extensions is being investigated. Eg. ``` c int *__attribute__((nontemporal)) p; ``` As a type attribute, will allow indirection of p with non-temporal cacheability hint. ## Features not considered for support ### VFP vector mode The short vector mode of the original VFP architecture is now deprecated, and unsupported in recent implementations of the Arm floating-point instructions set. There is no plan to support it through C extensions. ### Bit-banded memory access The bit-banded memory feature of certain Cortex-M cores is now regarded as being outside the architecture, and there is no plan to standardize its support.