Master the fundamental concepts of compiler optimization techniques through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
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 worksLoop unrolling duplicates the body to cut branch instructions per iteration and expose instruction-level parallelism. Compilers unroll at -O3; manual #pragma unroll or partial unrolling helps when the compiler is conservative about trip counts.
Process four elements per iteration with a cleanup loop for remainder.
cLoading…
-funroll-loops lets GCC decide automaticallyKeep the relevant documentation open while you implement. When your output disagrees with the reference, trace one failing case by hand before changing random lines.
You will implement manual loop unrolling on a reduction loop and compare against compiler-unrolled assembly. This exercise requires reporting when unrolling helped and when it regressed.
Unrolling a sum loop saves loop overhead, but on its own it does not make a reduction faster. Every add still waits for the previous one, because they all feed one accumulator. The real speed-up comes from splitting the sum across several independent accumulators, so adds overlap in the pipeline. Implement the unrolled sums for real (check that the result is unchanged), then use a simple cost model to see whether each version is limited by latency (the dependency chain) or by throughput (instructions per cycle).
cLoading…
The default array is array 1000 1.
j mod ACC. The remainder loop adds leftover elements to accumulator 0. The accumulators are then added together. Compare the result with a plain sum.main_iters * (2K + 3) + remainder * 5 + (ACC - 1). Each element costs a load and an add, and each loop iteration costs 3 overhead instructions. Code size: 2K + 3, plus 5 if K > 1 (the remainder loop), plus ACC - 1.ceil(instructions / W)), where chain = (the largest number of adds on any one accumulator + ACC - 1) * L. The bound is latency if chain >= the throughput term, else throughput.array: 1..100000 elements, latency: must be >= 1, issue: must be >= 1, and unroll K ACC: need 1 <= accumulators <= factor <= 64.cLoading…
Input:
cLoading…
Output:
cLoading…
Hidden tests cover a length that is not a multiple of K (remainder iterations), a latency of 1 (throughput-bound from the start), a narrow issue width, more accumulators than needed, a 1-element array, another seed, and invalid settings.