Arm Cortex-A76 Software Optimization Guide
Arm's own instruction-timing tables for the Cortex-A76 (PJDOC-466751330-7215, version 8.0, 46 pages, marked Non-Confidential and "Final, that is for a developed product"). Read for the ARM half of coverage edge 6 — the half uops-info explicitly said it could not cover.
Tier: T3, and the grade is the point. These are latency and throughput figures for Arm's own core, published by Arm, measured by nobody else. Under the load-bearing-claim rule that is the maker describing how well its product works, which is what T3 means — the same branch that puts a maintainer's own benchmark at T3 however reputable the venue. It is worth sitting beside uops-info, which is T2 because Abel and Reineke measure other people's silicon. So this spoke now knows x86 bit instructions from an independent measurement and ARM bit instructions from the vendor, and that asymmetry is not a filing detail: uops.info exists precisely because vendor tables and hardware sometimes disagree.
The document prints a 2019 copyright and a version number and states no publication date, so
published: records the year only.
What the columns mean
The definitions are given, and they are not the same quantity uops.info reports:
"Exec Latency is defined as the minimum latency seen by an operation dependent on an instruction in the described group."
"Execution Throughput is defined as the maximum throughput (in instructions per cycle) of the specified instruction group that can be achieved in the entirety of the Cortex-A76 microarchitecture."
Throughput here is instructions per cycle — bigger is better — where uops.info reports cycles per instruction, where smaller is better. Reading one table against the other without flipping that will invert every comparison.
The numbers
AArch64, from the integer and ASIMD tables:
| Instruction group | Instructions | Exec latency | Throughput | Pipelines |
|---|---|---|---|---|
| Count leading | CLS, CLZ |
1 | 3 | I |
| Reverse bits/bytes | RBIT, REV, REV16, REV32 |
1 | 3 | I |
| ASIMD count | CLS, CLZ, CNT |
2 | 2 | V |
| ASIMD bit reverse | RBIT |
2 | 2 | V |
| ASIMD arith, reduce, 4H/4S | ADDV, SADDLV, UADDLV |
3 | 1 | V1 |
| ASIMD arith, reduce, 8B/8H | ADDV, SADDLV, UADDLV |
5 | 1 | V1, V |
| ASIMD arith, reduce, 16B | ADDV, SADDLV, UADDLV |
6 | 1/2 | V1 |
Popcount is not one instruction here
This is the finding, and it changes the shape of the comparison this spoke has been making.
CNT counts set bits per byte lane, leaving sixteen separate counts in a 128-bit register. Getting
the one number a POPCNT returns takes a horizontal reduction as well, and the reduction is the
expensive half: ADDV over 16 byte lanes is 6 cycles of latency at one instruction every two
cycles, against CNT's 2 and 2. Three times the latency and a quarter of the throughput, for the
step that x86 does not need at all.
(My arithmetic, not the guide's claim: CNT + ADDV over one 128-bit register is 8 cycles of
dependent latency and is issue-limited to one such pair every two cycles. uops-info measures
VPOPCNTQ zmm at 3 cycles, one per cycle — for 512 bits. The per-cycle bit rate differs by
more than an order of magnitude, and almost none of the gap is the counting.)
The reduction cost also scales with lane count in a way the table makes legible: 3 cycles across 4
lanes, 5 across 8, 6 across 16. That is a tree, and its depth is the log of the lane count. Which
suggests the obvious structural answer for a real kernel — accumulate CNT results across many
registers with cheap pairwise adds and pay ADDV once at the end, rather than per register — though
this document prices instructions and does not discuss kernels, so that remains a reading rather than
a sourced claim.
Trailing zeros, by way of leading zeros
CLZ is here at latency 1 and throughput 3, alongside RBIT at the same cost. This guide's integer
tables list no trailing-zero count at all — there is a count-leading instruction and a bit-reverse
instruction and nothing between them. The standard AArch64 idiom is therefore RBIT then CLZ, which
these figures price at 2 cycles of dependent latency, two instructions on the same pipeline group.
x86 spends one instruction (TZCNT) where AArch64 spends two, and the two are cheap enough that the
difference is small. That is the opposite of the popcount result, so the two should not be
generalised from each other.
Scoped carefully: this says what the Cortex-A76 optimization guide's tables list. Later architecture versions add scalar bit-counting instructions, and nothing in this corpus sources that yet.
What it does not settle
One core, one generation, 2019, and the whole set is vendor-stated. Nothing here covers the wider Neoverse and Cortex-X cores, Apple's implementations, or SVE — where the vector length is not fixed and the reduction question changes shape. And no independent party has measured any of it. The equivalent of uops-info for AArch64 is the thing this spoke still lacks.
Related
uops-info · population-count · hamming-distance · bit-manipulation · branchless-programming · swar