Master the fundamental concepts of simd & vectorization through this focused micro-challenge.
SSE2 extends x86 registers to 128 bits (__m128i, __m128d). Intrinsics map directly to instructions like PADDQ and MULPD, giving deterministic vector code without inline assembly.
cLoading…
_mm_load_si128 requires 16-byte alignment_mm_loadu_si128 for heap buffersFor example, adding four 32-bit integers in one instruction uses one __m128i chunk instead of four scalar adds.
For this exercise, you will rewrite the scalar loop using SSE2 integer or double intrinsics. This task asks you to verify results bit-identical to scalar code before claiming speedup.
Keep the relevant datasheet, ISA manual, or architecture textbook chapter open while you implement. When your output disagrees with the reference trace on the same program, the bug is usually a mis-decoded opcode, a stale register read, or a flag bit left unchanged after arithmetic.
For this exercise, you will use those habits while implementing the requirement in the starter code. Microarchitectural product names change across CPU generations, but the control ideas (fetch, bypass, cache lines, vector lanes) stay stable enough to debug from first principles.
Vectorise element-wise add and mul on int32 arrays the way SSE2 code must: 4 lanes per 128-bit register, with scalar code before the vector loop until the pointer is 16-byte aligned (the prologue), aligned vector operations in the middle, and scalar code for the remainder after it (the epilogue). Verify the vector result against the scalar one and count the instructions saved.
One experiment per line: run OP N OFFSET. OP is add or mul, 1 ≤ N ≤ 100000, and OFFSET is the address of a[0] modulo 16 (a multiple of 4: 0, 4, 8 or 12). The arrays a, b, c share that alignment.
a[i] = 3i − 7, b[i] = (i mod 11) − 5, and c[i] = a[i] OP b[i] in 32-bit wrap-around arithmetic.
P = ((16 − OFFSET) mod 16) / 4 scalar elements, at most N.V = ⌊(N − P) / 4⌋ chunks of 4 lanes, all aligned.E = N − P − 4V elements, scalar.The scalar version costs N operations and the SIMD version P + V + E.
cLoading…
Print the first min(N, 8) results. The checksum is the 64-bit sum of all c[i]. If the vector result ever differed from the scalar one it would print (MISMATCH), so a correct solution always prints matches scalar.
Input:
cLoading…
Output:
cLoading…
_mm_loadu_si128, _mm_add_epi32, …) or GCC vector types both work. OFFSET is simulated, your real arrays have their own alignment, so use the unaligned load/store forms in your program; only the prologue/body/epilogue counts follow OFFSET._mm_mullo_epi32 is SSE4.1). If you use intrinsics for mul, build it from _mm_mul_epu32 and shuffles, or multiply lanes in scalar code.Hidden tests cover every offset, N smaller than the prologue, and large arrays where the prologue and epilogue are negligible.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it works