// Hand-C reference for bench_mono_dispatch — INDIRECT POLYMORPHIC variant. // // Same structure as bench_mono_indirect.c, but the fnptr is selected // per-iteration from a small array of FOUR distinct (and genuinely // different) `foo` implementations. This models a polymorphic class // hierarchy under hypothetical vdisp / dict-passing: the indirect // target varies, so the branch predictor cannot lock onto a single // destination. The four bodies are deliberately distinct (different // constants and operations) so clang's mergefunc cannot collapse them. // // This is the LOWER bound on what mono offers — predictor misses on // indirect dispatch when the call site sees more than one instance. // // IMPORTANT: this binary's stdout does NOT match the monomorphic // variants — different `foo` semantics produce a different final acc. // The harness skips the equality check for this binary; only the // timing matters here. // // Build: clang -O2 -o bench_mono_indirect_polymorphic bench_mono_indirect_polymorphic.c #include #include static int64_t foo_a(int64_t x) __attribute__((noinline)); static int64_t foo_b(int64_t x) __attribute__((noinline)); static int64_t foo_c(int64_t x) __attribute__((noinline)); static int64_t foo_d(int64_t x) __attribute__((noinline)); // Four genuinely different bodies — different constants, different // op shapes. Same instruction count and roughly same cost so the // "average" body cost matches the monomorphic case; what differs // is the dispatch shape. static int64_t foo_a(int64_t x) { return x * 1103515245 + 12345; } static int64_t foo_b(int64_t x) { return x * 1664525 + 1013904223; } static int64_t foo_c(int64_t x) { return x * 22695477 + 1; } static int64_t foo_d(int64_t x) { return x * 214013 + 2531011; } typedef int64_t (*foo_fn_t)(int64_t); static int64_t loop_call(foo_fn_t * volatile fps, int64_t i, int64_t acc) { while (i != 0) { // i & 3 cycles through the 4 fnptrs every iteration. foo_fn_t fp = fps[i & 3]; acc = acc + fp(acc + i); i = i - 1; } return acc; } int main(void) { foo_fn_t fps[4] = { &foo_a, &foo_b, &foo_c, &foo_d }; foo_fn_t * volatile fps_v = fps; printf("%lld\n", (long long)loop_call(fps_v, 100000000, 0)); return 0; }