> Combining these two tricks could lead to merge sort on par with the simple partition loop of QuickSort. However it’s just a mitigation. If instead of sorting a simple primitive value we would sort pointers to a struct. The comparison operator would have an extra load which immediately adds to the critical path. QuickSort is immune to this, even rather costly comparisons do not influence the ability to make progress. Of course if the comparison itself suffers from frequent branch misses, then that will limit the ability to overlap different stages of the iteration in the CPU pipeline.
In the benchmark code for the blog, he includes a benchmark that has indirection to illustrate this, though these results were not included in the article itself. On my machine I get:
$ CC=clang bazel build -c opt :all
$ bazel-bin/bench_sort --benchmark_filter=BM_IndirectionSort
-------------------------------------------------------------------------------------
Benchmark Time CPU Iterations
-------------------------------------------------------------------------------------
BM_IndirectionSort<1, std_sort> 64 ns 64 ns 10900000
BM_IndirectionSort<1, std_stable_sort> 89 ns 89 ns 7900000
BM_IndirectionSort<1, std_heap_sort> 112 ns 112 ns 6300000
BM_IndirectionSort<1, exp_gerbens::QuickSort> 26 ns 26 ns 27000000
BM_IndirectionSort<1, HeapSort> 96 ns 96 ns 7300000
BM_IndirectionMergeSort<1> 45 ns 45 ns 15500000