authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-07-12 20:11:56+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-12 23:52:13+02:00
log549a466dd1d5333e168cedfd0a7d6a634e37d694
tree645d57902e84bf4821967316a003c52b56f715ad
parent5b4e982169ab660a427da8b2c28c5eb7930362e2

std.Io.Reader: encourage inlining hot buffer check

Resolves: #24424

1 files changed, 12 insertions(+), 0 deletions(-)

lib/std/Io/Reader.zig+12
...@@ -1000,6 +1000,18 @@ pub fn fill(r: *Reader, n: usize) Error!void {...@@ -1000,6 +1000,18 @@ pub fn fill(r: *Reader, n: usize) Error!void {
1000 @branchHint(.likely);1000 @branchHint(.likely);
1001 return;1001 return;
1002 }1002 }
1003 return fillUnbuffered(r, n);
1004}
1005
1006/// This internal function is separated from `fill` to encourage optimizers to inline `fill`, hence
1007/// propagating its `@branchHint` to usage sites. If these functions are combined, `fill` is large
1008/// enough that LLVM is reluctant to inline it, forcing usages of APIs like `takeInt` to go through
1009/// an expensive runtime function call just to figure out that the data is, in fact, already in the
1010/// buffer.
1011///
1012/// Missing this optimization can result in wall-clock time for the most affected benchmarks
1013/// increasing by a factor of 5 or more.
1014fn fillUnbuffered(r: *Reader, n: usize) Error!void {
1003 if (r.seek + n <= r.buffer.len) while (true) {1015 if (r.seek + n <= r.buffer.len) while (true) {
1004 const end_cap = r.buffer[r.end..];1016 const end_cap = r.buffer[r.end..];
1005 var writer: Writer = .fixed(end_cap);1017 var writer: Writer = .fixed(end_cap);