Understanding AVX2 Vector Processors and Register Files: A Practical Guide for HPC Programmers

Introduction

High-performance computing (HPC) applications spend most of their execution time performing arithmetic operations on large arrays. Whether solving partial differential equations, running finite element simulations, or executing phase-field models, performance ultimately depends on how efficiently the processor can execute vector operations.

Modern CPUs achieve this efficiency through SIMD (Single Instruction, Multiple Data) execution, where one instruction performs the same operation on multiple data elements simultaneously.

To optimize scientific codes, it is therefore important to understand three fundamental architectural components:

  1. Vector Processing Units (VPUs) – the hardware that performs computations.

  2. Vector Register Files – the high-speed storage that feeds data to the VPUs.

  3. The relationship between vector width, register capacity, and execution throughput.

This article explains these concepts using the Intel Core i5-8300H processor, which supports the AVX2 instruction set.


1. Hardware Overview

The processor considered here contains

  • 4 physical CPU cores

  • AVX2 vector instruction set

  • 256-bit vector units

  • Single-precision (32-bit) floating-point arithmetic

Each core operates independently and contains its own execution hardware and register file.

modern CPU

2. Vector Processing Units

A Vector Processing Unit (VPU) is the arithmetic engine responsible for performing SIMD computations.

Unlike a traditional scalar processor, which computes one floating-point value at a time, a vector processor computes multiple values simultaneously.

For AVX2,

\[ \text{Vector Width}=256 \space \text{bits} \]

Since a single-precision floating-point number occupies

\[ {32} \space \text{bits} \]

the number of floating-point values processed simultaneously is

\[ \frac{256}{32}=8 \]

Thus,

One AVX2 instruction can process eight single-precision floating-point values in one vector operation.

This is often referred to as an 8-wide SIMD architecture shown above in Figure.


2.1 A Concrete Example: Vector Addition

Abstract element counts become much clearer with an actual example.

Consider two arrays, each holding exactly 8 single-precision values — the same width as one YMM register:

A = [1, 2, 3, 4, 5, 6, 7, 8]
B = [1, 2, 3, 4, 5, 6, 7, 8]

The goal is to compute the element-wise sum

\[ C = A + B \]

Scalar execution (without SIMD) would require 8 separate add instructions, one per element:

C[0] = A[0] + B[0]
C[1] = A[1] + B[1]
C[2] = A[2] + B[2]
C[3] = A[3] + B[3]
C[4] = A[4] + B[4]
C[5] = A[5] + B[5]
C[6] = A[6] + B[6]
C[7] = A[7] + B[7]

AVX2 execution instead loads all 8 elements of A into one YMM register, all 8 elements of B into another YMM register, and issues a single vector-add instruction:

YMM0 = [1, 2, 3, 4, 5, 6, 7, 8]      A
YMM1 = [1, 2, 3, 4, 5, 6, 7, 8]      B

VADDPS YMM2, YMM0, YMM1               one instruction, 8 additions

The result is produced in a single step:

C = YMM2 = [2, 4, 6, 8, 10, 12, 14, 16]

This is the practical meaning of “8-wide SIMD” introduced above: one VADDPS instruction replaces eight scalar ADD instructions, because the 256-bit register holds all eight operand pairs at once and the 256-bit vector ALU adds them in parallel.

This example also sets up a natural follow-up question, addressed in a companion article: addition is a single arithmetic operation, but many HPC kernels (matrix multiplication, convolutions, stencil computations) require a multiply followed by an addC = A × B + D. The question of whether that combined operation can also be done in a single vector step, rather than two, is answered by Fused Multiply-Add (FMA), covered next.


3. Vector Registers

The VPU cannot directly read data from main memory.

Instead, operands are first loaded into vector registers, which act as extremely fast local storage located beside the execution units.

For AVX2,

  • 16 vector registers per core

  • Registers named

YMM0
YMM1
...
YMM15

Each register stores

  • 256 bits

  • or

  • 8 single-precision floating-point values.

Therefore,

\[ 16\times8=128 \]

Each CPU core can store

128 single-precision floating-point values inside its vector register file.

It is important to distinguish between storage capacity and processing capability.

The register file stores data, while the vector processor performs computations.

vpu registers

4. Why Register Width Matches Vector Width

One elegant feature of SIMD processor design is that the register width exactly matches the execution width.

registerToVPU

This one-to-one relationship provides several advantages:

  • no register splitting

  • no partial execution

  • full utilization of the arithmetic pipelines

  • one vector instruction completely fills the execution hardware

Consequently, every AVX2 instruction naturally operates on an entire register.


5. Scaling to Multiple CPU Cores

Each CPU core possesses its own independent vector hardware.

For a processor with four cores,

Register Capacity

Each core stores

\[ 128\text{ elements} \]

Therefore,

\[ 4\times128=512 \]

The complete processor can collectively hold

512 single-precision floating-point values inside its vector registers.


Processing Throughput

Each core computes

\[ 8 \]

floating-point values per vector operation.

Across four cores,

\[ 4\times8=32 \]

Therefore,

The processor can compute 32 single-precision floating-point values simultaneously when all four cores execute vector instructions in parallel.


6. Example: Processing a 512-Element Array

Suppose a one-dimensional array contains

\[ 512 \]

single-precision values.

When parallelized evenly across four cores,

each core receives

\[ \frac{512}{4}=128 \]

elements.

Interestingly,

128 elements exactly matches the storage capacity of each core’s vector register file.

Thus,

Core 0  128 elements
Core 1  128 elements
Core 2  128 elements
Core 3  128 elements

Each core processes

8 elements per vector instruction.

Therefore,

\[ \frac{128}{8}=16 \]

vector operations are required per core.

Since all four cores operate simultaneously,

the entire processor executes

\[ 32 \]

elements during each vector step.

Hence,

\[ \frac{512}{32}=16 \]

vector-processing steps are required to complete the computation.

This demonstrates that the workload perfectly matches both the available register capacity and the vector execution width of the processor.


7. What This Means for HPC Developers

Understanding these architectural limits provides valuable insight into performance optimization.

When writing scientific software, efficient SIMD execution depends on several factors:

  • writing vectorizable loops

  • minimizing dependencies between iterations

  • ensuring data is contiguous in memory

  • aligning memory accesses where possible

  • exposing enough independent work for all CPU cores

Compilers such as Intel oneAPI, GCC, LLVM, and NVIDIA HPC SDK attempt to generate vector instructions automatically. However, achieving high performance still requires writing code that maps naturally onto the processor’s vector architecture.


8. An Important Clarification

A common misconception is that because the four cores collectively have enough register space to hold 512 floating-point values, the entire 512-element array is loaded into registers at once and then processed over 16 cycles.

In reality, modern processors do not work this way.

Vector registers are temporary working storage, not a cache for the whole problem. During execution, the processor repeatedly:

  1. loads a small block of data (typically one 256-bit vector per instruction) from cache into registers,

  2. performs the vector computation,

  3. writes the result back (or keeps it in registers if reused),

  4. repeats this process for the next block.

The calculation

\[ \frac{512}{32}=16 \]

should therefore be interpreted as 16 vector-processing batches (or iterations) assuming ideal vectorization across all four cores, not as the entire array residing in the register file simultaneously. The register capacity tells us the amount of temporary state available to the processor, while the throughput calculation tells us how many elements can be processed in parallel at any instant.


Conclusion

Efficient HPC programming is not only about writing correct algorithms but also about understanding the underlying hardware.

For an AVX2 processor with four physical cores:

  • Each core contains one 256-bit vector processing unit.

  • Each vector instruction processes 8 single-precision floating-point values.

  • Each core provides 16 vector registers, storing 128 floating-point values in total.

  • Across four cores, the processor executes 32 floating-point values in parallel during each vector-processing step.

  • Consequently, a 512-element single-precision array requires 16 vector-processing batches when fully vectorized and evenly distributed across all four cores.

This architectural perspective helps HPC developers understand why vectorization is so important, how compiler-generated SIMD code maps to the hardware, and why maximizing data locality and vector-friendly loop structures is essential for achieving high performance.