Skip to content

Instantly share code, notes, and snippets.

@gnzlbg gnzlbg/
Last active Feb 19, 2019

What would you like to do?

So @eddyb and me talked about this, and this comment summarizes that.

@eddyb proposes a bench_input function with the operational semantics of the identity function, that the optimizer is encouraged / hinted to treat as an unknown pure function (think extern { const fn bench_input<T>(T) -> T; }).

That is, the statement bench_input(expr); can be completely optimized away. Given:

let mut v = Vec::with_capacity(1);
let v = bench_input(v); 

the bound check in v[0] cannot be removed because bench_input could return any vector (e.g. Vec::new()). Also, because the return value depends on the input, the write of 1 to memory in the push must be flushed before calling bench_input.

However, because the v[0]; result is not used, that could be optimized away, and because v is not used, and bench_input is pure, actually the whole snippet can be optimized away.

To prevent that from happening, @eddyb proposes to add bench_output(x), which has the same operational semantics as mem::forget: it leaks its value, runs no destructors, but which the optimizer is encouraged to treat as an unknown function with read-only side-effects that depend on x.

With that, one can change the snippet above to:

let mut v = Vec::with_capacity(1);
let v = bench_input(v); 

to prevent the code from being removed.

Note: bench_output cannot be implemented as fn bench_output<T>(x: T) { bench_input(x); }, because that would mean that it can be removed. It must therefore be a special API.

Something like black_box, as proposed in this RFC, would then be implemented as:

fn black_box<T>(x: T) -> T {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.