A data hazard occurs when one instruction needs a value produced or modified by another, preventing the CPU from executing both simultaneously. The dependent instruction must wait, limiting instruction-level parallelism (ILP). section 12.3
const n = 1_000_000
func add(s [2]int64) [2]int64 {
for i := 0; i < n; i++ { #1
s[0]++ #2
if s[0]%2 == 0 { #3
s[1]++
}
}
return s
}
Trace the loop as three operations: increment s[0], test the new value, and conditionally increment s[1]. The test depends on the first increment, creating a data hazard. section 12.3
The dependency is easy to miss because the code is short. In `s[0]++` followed by `if s[0]%2 == 0`, the condition must observe the updated s[0]. The CPU cannot safely run these operations in parallel, although independent operations may still overlap. section 12.3
Reduce the dependency when the computation permits it:
- Copy the old value into a temporary, update s[0], and test the old value instead. This changes the condition to `if v%2 != 0`, allowing both increment steps to execute in parallel. section 12.3
- Treat forwarding as a CPU-level mitigation rather than a complete solution: it bypasses writing to a register but does not remove the underlying dependency. section 12.3
- Do not confuse data hazards with control hazards from branching or structural hazards from competing for the same resource; those require different analyses. section 12.3
Comparing the loop forms
The original `add` loop increments s[0] and then checks the updated value, so the check waits for the increment. The `add2` loop saves the old value in v, updates s[0], and checks v; the two increment paths can then run in parallel while preserving the intended result. section 12.3
