.p2align"pee-two-align"
A directive padding the next instruction to a power-of-two address boundary. Before a loop it means the compiler cared about how that loop sits in the instruction cache.
"There is a .p2align before the loop body — it wants the hot loop aligned."
ABIsaid as letters; Application Binary Interface
The conventions that let separately compiled code interoperate: which registers carry arguments, how values are returned, who preserves what, how the stack is aligned.
"That is an ABI break — you cannot change the struct layout in a published header."
addressing mode
The rule for computing a memory address from parts. x86-64 offers [base + index*scale + displacement] where scale is 1, 2, 4 or 8 — one instruction covers most array indexing.
"The whole array index folded into the addressing mode, so there is no separate multiply."
aliasing
Two pointers possibly referring to the same memory. If the compiler cannot rule it out, it must reload after every store — which blocks a large class of optimisations.
"It reloads every iteration because the two pointers might alias. restrict fixes it."
alignment
The requirement that an address be a multiple of the access size. x86 tolerates misalignment with a penalty; some ARM operations do not tolerate it at all. Also the reason structs contain padding.
"That struct is 24 bytes not 20, because of alignment padding."
architectural vs physical register
Architectural registers are the names in the instruction set (rax, w0). Physical registers are the actual silicon, of which there are far more. Only the architectural ones appear in assembly.
"There are 16 architectural registers and about 200 physical ones on this core."
autovectorisation
The compiler turning a scalar loop into a vector one by itself. It fails often, and usually for a nameable reason: possible aliasing, unknown trip count, or a reduction it may not reorder.
"It refused to vectorise because floating-point addition is not associative and it will not reorder without -ffast-math."
branch
A conditional or unconditional jump. The unit that branch prediction operates on, and the thing whose cost is unpredictable.
"That branch is unpredictable, which is why the branchless version wins here."
cache hierarchy
L1 (~4 cycles), L2 (~14), L3 (~40), DRAM (~200+). This is fiction three: one mov instruction, two orders of magnitude of cost.
"It fits in L2 now, which is the whole speedup — the instruction count barely moved."
cache line
The unit of transfer between cache and memory, 64 bytes on x86-64 and Apple silicon. You never load one byte; you load its whole line.
"Those two fields are on the same cache line, which is why the false sharing hurts."
caller-saved / callee-savedalso volatile / non-volatile
Caller-saved registers may be destroyed by a call, so the caller preserves anything it still needs. Callee-saved registers must be restored by the function using them. Which is which is fixed by the ABI.
"It pushed rbx in the prologue because rbx is callee-saved."
calling convention
The argument-passing part of an ABI. SysV AMD64 (Linux/macOS x86-64) uses rdi, rsi, rdx, rcx, r8, r9. AAPCS64 (ARM64) uses x0–x7. Windows x64 uses rcx, rdx, r8, r9 — different, which is why ABI matters.
"First argument is in rdi on SysV but rcx on Windows, so that hand-written asm is not portable."
cmov / csel"see-move" / "see-sel"
Conditional move (x86) and conditional select (ARM64): pick one of two values based on flags, without branching. The compiler emits these when it judges a branch would mispredict.
"It turned the if into a cmov, so there is no branch to mispredict."
constant folding / propagation
Evaluating constant expressions at compile time (folding) and carrying known values forward through the code (propagation).
"The whole call folded to a single constant — there is no code left."
CSEsaid as letters; Common Subexpression Elimination
Computing a repeated expression once and reusing the result.
"CSE hoisted the shared index calculation, so it only happens once."
dependency chainalso critical path
A sequence where each operation needs the previous result, so none can overlap. Chain length, not instruction count, sets the floor on execution time.
"The sum is one long dependency chain — use four accumulators and it gets four times faster."
disassembly
Recovering assembly text from machine code. What a debugger or profiler shows you, and distinct from compiler output because it reflects the linked, final binary.
"Check the disassembly rather than Godbolt — I want to see what actually shipped."
endbr64"end-branch 64"
A control-flow-integrity landing pad. It marks a legal indirect-branch target and does no computation. Ignore it when reading logic.
"Ignore the endbr64, it is CFI padding, not part of the function."
execution port
A hardware path to a functional unit. Each port handles specific operation kinds, so instructions compete for ports rather than for some generic "CPU".
"There are only two load ports, so that loop is port-limited."
false sharing
Two threads writing different variables that share a cache line, forcing the line to bounce between cores. Correct code, terrible performance.
"Pad the per-thread counters to a cache line each and the false sharing goes away."
flags / condition codes
A small register of single bits set as a side effect of arithmetic — zero, sign, carry, overflow. Comparisons set flags; conditional jumps read them. This is how assembly has no booleans.
"cmp sets the flags and je reads them — there is no boolean value anywhere in between."
frame pointerrbp on x86-64, x29 on ARM64
A register holding a fixed reference point into the current frame. Optional for correctness, which is why compilers omit it — and omitting it is what breaks naive stack unwinding.
"Built with -fomit-frame-pointer, which is why the profiler cannot walk the stack."
immediate
A constant encoded directly in the instruction, rather than read from a register or memory.
"That is an immediate, so the constant costs nothing to load."
induction variable
A variable that changes by a fixed amount each iteration — a loop counter, or a pointer walking an array. Compilers rewrite these aggressively, which is why your counter often vanishes.
"The index variable is gone; it strength-reduced it into a pointer increment."
inlining
Replacing a call with the callee body. The single most valuable optimisation, because it removes call overhead and then enables every other optimisation across the boundary.
"Once it inlined, constant propagation deleted half the function."
IPCsaid as letters; instructions per cycle
Average instructions retired per cycle. A headline number in profilers. Low IPC means stalling — but high IPC just means executing a lot, not doing useful work.
"IPC is 0.4, so it is stalled on memory, not compute-bound."
ISAsaid as letters; Instruction Set Architecture
The documented contract between compiler and CPU: which instructions exist, what they mean, what registers there are. Crucially it is an *interface*, not a description of the silicon.
"x86-64 is the ISA. What actually executes is micro-ops, and that gap is the point."
lane
One element position within a vector register. A 256-bit register holds 8 lanes of 32-bit values.
"The horizontal sum is the slow part — combining lanes is awkward on every ISA."
latency vs throughput
Latency is how long one operation takes end to end. Throughput is how many can start per cycle. A multiply might have 3-cycle latency and 1-per-cycle throughput — so three independent multiplies take about the same time as one.
"The multiply is 3-cycle latency but fully pipelined, so it only hurts if you are in a dependency chain."
lea"L-E-A", or "lee-uh"; short for Load Effective Address
Computes an address but does not access memory. In practice it is a free multiply-and-add, and the compiler uses it constantly for plain arithmetic.
"lea rax, [rdi+rdi*2] is a multiply by three. Nothing is being loaded."
LICM"lick-em"; Loop-Invariant Code Motion
Moving computations that do not change between iterations out of the loop body.
"LICM could not hoist that load because it cannot prove the pointers do not alias."
link registerlr, or x30 on ARM64
On ARM64 the return address goes in a register rather than being pushed by the call. Non-leaf functions must save it themselves — which is why ARM64 prologues look different from x86.
"It saves the link register because it makes a call, so it is not a leaf."
llvm-mca"L-L-V-M M-C-A"; Machine Code Analyzer
A static pipeline simulator: give it a block and it estimates throughput and port pressure. It models the core and knows nothing about caches or branches.
"llvm-mca says it is port-bound, but that ignores the cache misses, so measure it."
macro-op fusion
The decoder combining two adjacent instructions into one µop — typically a compare and the branch that follows it. So two instructions can cost less than two.
"The cmp and jne fuse, so that pair is effectively one operation."
name mangling
Encoding types and namespaces into a symbol name so overloads can coexist. Why Rust and C++ symbols look like noise, and why disassemblers offer a demangle option.
"Turn on demangling — those symbols are unreadable otherwise."
NEON / SVE
ARM vector extensions. NEON is fixed 128-bit and is what your M1 uses. SVE is variable-width and appears on newer server parts.
"On ARM it is NEON, so 128-bit — half the width of the AVX2 version."
out-of-order executionoften "OoO", said "oh-oh-oh"
Executing instructions as their inputs become ready rather than in program order, then committing results in order. This is fiction two: the listing is a dependency graph, not a script.
"Order in the listing barely matters — it is out-of-order, so what matters is the dependency chain."
padding
Unused bytes inserted between struct fields to satisfy alignment. Field order changes how much you get, which is why reordering a struct can shrink it.
"Reorder the fields largest-first and you drop eight bytes of padding."
pipeline
Splitting instruction processing into stages so many instructions are in flight at once. Depth is why a mispredicted branch is expensive: the whole pipeline must be discarded.
"A mispredict costs about fifteen cycles because that is roughly the pipeline depth."
PLT / GOTsaid as letters; Procedure Linkage Table / Global Offset Table
Indirection tables used for calls into shared libraries and for position-independent code. A call through the PLT costs an extra jump.
"That call goes through the PLT, so it is a cross-library call."
port pressure
Contention for a specific execution port. A loop can be limited by one port while the rest of the core idles.
"There is port pressure on the shuffle unit — spreading the work across ports would help."
prefetch
Fetching data before it is requested. Hardware does this automatically for predictable strides; irregular access patterns defeat it, which is most of why pointer chasing is slow.
"Sequential access lets the prefetcher work; the linked list defeats it completely."
prologue / epilogue
The setup and teardown code at the start and end of a function: establishing the frame, saving callee-saved registers, and undoing both.
"The prologue is push rbp / mov rbp, rsp — everything after that is the actual function."
red zone
128 bytes below the stack pointer that a leaf function may use without adjusting rsp, per the SysV ABI. It is why small functions sometimes have no visible stack manipulation.
"It is using the red zone, so there is no sub rsp at all."
register
One of a small fixed set of storage locations inside the CPU. x86-64 has 16 general-purpose registers; ARM64 has 31. They are the fastest storage that exists and the compiler spends most of its effort deciding who gets one.
"It ran out of registers and started spilling to the stack."
register renaming
The CPU maps the ~16 architectural register names onto hundreds of physical registers, so two instructions using the same name need not depend on each other. This is fiction one, dismantled.
"xor eax, eax is not just a zero — renaming means it breaks the dependency on the previous value of eax."
restrict / noalias
A promise that a pointer is the only route to its data. restrict in C; Rust gives it to the compiler for free via &mut, which is the concrete cash value of the borrow checker.
"Rust emits noalias on &mut, so it gets this optimisation without an annotation."
retireTRAP: nothing to do with finishing work
The final in-order commit of an instruction, making its effects architecturally visible. An instruction can execute and then never retire, if it was speculative and wrong.
"It executed but never retired — the branch was mispredicted."
SIMD"sim-dee"; Single Instruction Multiple Data
One instruction operating on several values at once, held in a wide vector register.
"That loop is SIMD now — eight lanes per instruction."
speculation
Executing past a branch before knowing the outcome, discarding the work if wrong. Essential for performance, and the root of the Spectre class of vulnerabilities.
"It speculates through the bounds check, which is exactly what Spectre abuses."
spill
Moving a value out of a register into stack memory because registers ran out. Spills are the visible symptom of register pressure.
"Unrolling that loop caused spills, which is why it got slower."
stack frame
The region of stack belonging to one function call: saved registers, locals, spills. Not a language feature — it is a convention maintained by generated code.
"The frame is 48 bytes, so there are a lot of spilled locals."
stallalso bubble
A cycle in which the pipeline cannot make progress, usually waiting for data. The thing you are actually hunting when optimising.
"Most of the time is stalls on last-level cache misses."
store forwarding
Feeding a just-written value directly to a dependent load instead of waiting for the cache. When it fails — partial overlap, wrong size — you get a large surprise penalty.
"That is a store-forwarding stall from writing bytes and reading a word."
strength reduction
Replacing an expensive operation with a cheaper equivalent — multiply by a shift-and-add, divide by a multiply-and-shift.
"That multiply by 0x55555556 is strength-reduced division by three."
superscalar
Able to issue more than one instruction per cycle. Modern cores issue four to eight, which is why instruction count is such a poor proxy for time.
"It is four-wide, so those independent adds are effectively free."
tail call
A call in final position, which can reuse the current frame — so it compiles to a jump rather than a call, and does not grow the stack.
"That is a tail call — see the jmp instead of a call, so recursion here cannot overflow."
test vs cmp
cmp a, b sets flags as if subtracting. test a, b sets flags as if AND-ing. test rax, rax is the idiomatic zero or null check because it is smaller than comparing against zero.
"test rax, rax then je — that is a null check."
TLBsaid as letters; Translation Lookaside Buffer
A cache of virtual-to-physical page translations. A TLB miss costs a page-table walk, and large working sets can be TLB-bound rather than data-bound.
"Huge pages helped, so it was TLB pressure rather than cache misses."
two's complement"tooz complement"
The near-universal encoding for signed integers: the top bit means negative, and negation is invert-then-add-one. Its consequence is that the same add instruction works for signed and unsigned.
"Addition is the same instruction either way — two's complement is why signedness only shows up in the compare."
UBsaid as letters; undefined behaviour
Program behaviour the language standard does not define, which permits the compiler to assume it never happens. Signed overflow in C is UB, and that assumption is why loops optimise as well as they do.
"It assumed no signed overflow — that is UB, so it is allowed to."
unrolling
Duplicating a loop body so each iteration does more work, reducing loop overhead and exposing instruction-level parallelism. Costs code size and can cause spills.
"It unrolled by four, which is why the body looks repetitive."
wordTRAP: on x86 a "word" is 16 bits, not 32 or 64
A size, and the size depends on the architecture and its history. On x86: byte 8, word 16, dword 32, qword 64. On ARM64 documentation, "word" usually means 32 bits.
"DWORD PTR means it is a 32-bit access, despite dword sounding like double the machine width."
xmm / ymm / zmm
x86 vector registers of 128, 256 and 512 bits, from SSE, AVX and AVX-512 respectively. The name in the listing tells you the width immediately.
"It is using ymm, so AVX2, so 256-bit — eight ints at a time."
zero extension / sign extension
Widening a narrow value to a wider register. Zero extension fills with zeros (unsigned); sign extension copies the top bit (signed). movzx and movsx on x86; uxtw/sxtw on ARM64.
"It used movzx, so that value is being treated as unsigned."
µop"micro-op"; also written uop
The internal operation a CPU actually executes. x86 instructions are decoded into one or more µops. This is fiction four: the ISA is an interface, µops are the work.
"That one instruction is three µops, so it is not as cheap as the count suggests."
Nothing matches that filter.