Assembly AVX — Advanced Vector Extensions for 256-bit SIMD
In this tutorial, you will learn about Assembly AVX. We cover key concepts, practical examples, and best practices to help you master this topic.
AVX extends SSE to 256-bit YMM registers with non-destructive 3-operand syntax, enabling 8 single-precision or 4 double-precision operations per instruction.
What You'll Learn
- YMM registers (256-bit)
- AVX 3-operand syntax
- VEX prefix encoding
- AVX2 integer operations
- AVX-512 overview
Why It Matters
AVX doubles SSE's throughput and adds non-destructive operations. Doda Browser uses AVX for accelerated image decoding and CSS filter effects in its Rendering Pipeline.
Real-World Use
High-performance computing, video encoding/decoding, Machine Learning inference, scientific simulations, and any workload with regular data-parallel patterns.
flowchart LR
A["AVX"] --> B["YMM 256-bit"]
A --> C["3-Operand"]
A --> D["VEX Prefix"]
B --> E["8 x Float"]
B --> F["4 x Double"]
C --> G["dest, src1, src2"]
D --> H["No SSE penalty"]
style A fill:#2563eb,stroke:#2563eb,color:#fff
style B fill:#dbeafe,stroke:#2563eb,color:#1e40af
style C fill:#dbeafe,stroke:#2563eb,color:#1e40af
style D fill:#dbeafe,stroke:#2563eb,color:#1e40af
style E fill:#dbeafe,stroke:#2563eb,color:#1e40af
YMM Register Layout
YMM0: [ f7 | f6 | f5 | f4 | f3 | f2 | f1 | f0 ] floats
YMM0: [ d3 | d2 | d1 | d0 ] doubles
bit255 bit0
16 YMM registers in 64-bit mode (YMM0-YMM15). The lower half of each YMM register is the corresponding XMM register.
Basic AVX Operations
section .data
a dd 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0
b dd 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0
result dd 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
section .text
vmovaps ymm0, [a] ; load 8 floats
vmovaps ymm1, [b]
vaddps ymm2, ymm0, ymm1 ; ymm2 = ymm0 + ymm1 (non-destructive)
vmovaps [result], ymm2
; result = [10, 12, 14, 16, 18, 20, 22, 24]
3-Operand Syntax
; AVX: dest, src1, src2 (src1 and src2 are preserved)
vaddps ymm2, ymm0, ymm1 ; ymm2 = ymm0 + ymm1
; SSE: dest, src (dest is overwritten)
addps xmm0, xmm1 ; xmm0 += xmm1
; The non-destructive syntax reduces register pressure
AVX Arithmetic
vmovaps ; move aligned packed single
vmovups ; move unaligned packed single
vaddps ; packed add (float)
vsubps ; packed subtract (float)
vmulps ; packed multiply (float)
vdivps ; packed divide (float)
vsqrtps ; packed square root
vaddpd ; packed add (double)
vsubpd ; packed subtract (double)
vmulpd ; packed multiply (double)
vdivpd ; packed divide (double)
vhaddps ; horizontal add (float)
vhsubps ; horizontal subtract
AVX Fused Multiply-Add
; FMA3 — fused multiply-add (Haswell+)
; dest = src1 * src2 + src3
section .data
a dd 2.0, 3.0, 4.0, 5.0
b dd 3.0, 4.0, 5.0, 6.0
c dd 1.0, 1.0, 1.0, 1.0
section .text
vmovaps xmm0, [a]
vmovaps xmm1, [b]
vmovaps xmm2, [c]
vfmadd132ps xmm0, xmm2, xmm1 ; xmm0 = xmm0*xmm1 + xmm2
vfmadd213ps xmm0, xmm1, xmm2 ; xmm0 = xmm0*xmm1 + xmm2
vfmadd231ps xmm0, xmm1, xmm2 ; xmm0 = xmm1*xmm2 + xmm0
AVX2 Integer Operations
AVX2 extends integer SIMD to 256-bit:
section .data
a db 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
db 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
section .text
vmovdqu ymm0, [a] ; 32 bytes
vpaddb ymm1, ymm0, ymm0 ; double all bytes
vpshufb ymm1, ymm0, ymm2 ; shuffle bytes
; Gather (AVX2)
; vpgatherdd — gather dwords from memory
mov rax, array_base
vpgatherdd xmm0, [rax + xmm1 * 4], xmm2
AVX-512 Overview
; AVX-512 extends to 512-bit ZMM registers (32 registers)
; 16 single-precision or 8 double-precision per instruction
; Mask registers (k0-k7) for predication
; Opmask conditional operations
; Example (AVX-512F)
; vaddps zmm0, zmm1, zmm2 ; 16 floats at once
; vaddpd zmm0 {k1}, zmm1, zmm2 ; masked operation
; Requires: Skylake-X (consumer) or Xeon Phi (Knight's Landing)
VEX Prefix Advantages
; SSE: 2-operand, overwrites source
addps xmm0, xmm1 ; xmm0 += xmm1
; AVX: 3-operand, preserves both sources
vaddps xmm2, xmm0, xmm1 ; xmm2 = xmm0 + xmm1
; Benefits:
; + Fewer register copies (less register pressure)
; + Cleaner code
; + No false dependencies (partial register stalls)
; + Can zero registers with vxorps (no dependency)
Memory Alignment
section .data
; Align data for AVX
align 32
a dd 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0
section .text
; vmovaps requires 32-byte alignment
vmovaps ymm0, [a] ; aligned load (fast)
; vmovups for unaligned
vmovups ymm0, [rsi + rcx * 4] ; unaligned (may be slower)
Common Mistakes
1. Mixing AVX and SSE instructions
Transitioning between SSE and AVX has a performance penalty (state change). Use AVX throughout hot code.
2. Forgetting VEX prefix
Modern assemblers auto-prefix AVX instructions. Writing SSE opcodes with YMM registers is invalid.
3. Alignment with vmovaps
vmovaps requires 32-byte alignment. vmovups works with any alignment. Use align 32 in data sections.
4. Not checking AVX support
Older CPUs (pre-Sandy Bridge) lack AVX. Use CPUID to detect. Most x86-64 CPUs from 2011+ have AVX.
5. YMM register save/restore overhead
Context switches save/restore YMM state. Heavy AVX use can cause system-wide slowdown (AVX frequency scaling).
Practice Questions
1. What is the width of a YMM register?
256 bits (compared to 128 bits for XMM).
2. What advantage does AVX's 3-operand syntax provide?
Non-destructive operations preserve source operands, reducing register pressure and eliminating unnecessary copies.
3. How many floats can one AVX instruction Process?
8 single-precision floats per instruction.
4. What is AVX-512?
An extension to 512-bit ZMM registers with 32 registers and mask-based predication for conditional operations.
Challenge: Write an AVX function that computes the element-wise maximum of two 256-bit float vectors.
Solution
; void max_vectors(float* a, float* b, float* out)
; a in RDI, b in RSI, out in RDX
max_vectors:
vmovaps ymm0, [rdi]
vmovaps ymm1, [rsi]
vmaxps ymm2, ymm0, ymm1
vmovaps [rdx], ymm2
vzeroupper ; clear upper YMM state
ret
FAQ
{{< faq question="Do all x86-64 CPUs support AVX?" >}} No. Intel Sandy Bridge (2011) and AMD Bulldozer (2011) added AVX. Older CPUs lack it. Check with CPUID before using. {{< /faq >}}
{{< faq question="What is the performance penalty of mixing SSE and AVX?" >>
Transitioning from SSE to AVX causes a ~50-cycle state change penalty. Avoid mixing in hot code or use vzeroupper to clear state.
{{< /faq >}}
{{< faq question="What is AVX frequency scaling?" >}} Heavy 256-bit/512-bit instructions consume more power, causing the CPU to downclock. AVX-512 has the most aggressive scaling. {{< /faq >}}
{{< faq question="Can I use AVX on 32-bit x86?" >}} Yes, AVX works on 32-bit x86 with OS support (OSXSAVE feature bit). However, 32-bit has only 8 YMM registers. {{< /faq >}}
{{< faq question="What is vzeroupper?" >}} An instruction that zeros the upper 128 bits of all YMM registers, avoiding SSE/AVX transition penalties. {{< /faq >}}
Mini Project
Write an AVX function that computes the element-wise sum of two 8-float arrays.
section .data
align 32
a dd 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0
b dd 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0
section .bss
align 32
result resd 8
section .text
global _start
_start:
vmovaps ymm0, [a]
vmovaps ymm1, [b]
vaddps ymm2, ymm0, ymm1
vmovaps [result], ymm2
; result = [10, 12, 14, 16, 18, 20, 22, 24]
vzeroupper
mov rax, 60
xor rdi, rdi
syscall
What's Next
Now that you understand AVX, proceed to multi-file assembly projects.
| Topic | Description | Link |
|---|---|---|
| Multifile | Multi-file projects | {{< ref "18-multifile" >}} |
| SSE | 128-bit SIMD | {{< ref "16-sse" >}} |
| Floating-point | Scalar FP | {{< ref "15-floating-point" >}} |
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro