-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New name for hint::black_box: pretend_used #74853
Conversation
r? @shepmaster (rust_highfive has picked a reviewer for you, use r? to override) |
I'd like to make it clear that I opened this PR primarily as a way to direct conversation from #64102 (comment) for a concrete change. If folks don't like the proposed name, I am happy to close this and continue discussion in #64102. |
☔ The latest upstream changes (presumably #73265) made this pull request unmergeable. Please resolve the merge conflicts. |
|
I like the |
Wikipedia describes black boxes as having an opaque implementation, so one option might be simply |
The intention (though I agree the name doesn't quite communicate this) was that the compiler should assume that
I think my take here is, as above, that the compiler can't constant-fold across
That would work if the body was actually opaque to the compiler, but I don't think that's actually the case. The compiler does still get some insight into what goes on, as per rust-lang/rfcs#2360 (comment), and so calling it |
@tmiasko I'll respond to your comment over here.
Actually, I think the existing |
@jonhoo Good point. Another suggestion: As in, we're telling the compiler to pretend that value is used to calculate a new result, even though it isn't. |
Oooh, I quite like |
The current name is a legacy from before RFC 2360. The RFC calls the method `bench_black_box`, though acknowledges that this name is not be ideal either. The main objection to the name during and since the RFC is that it is not truly a black box to the compiler. Instead, the hint only encourages the compiler to consider the passed-in value used. This in the hope that the compiler will materialize that value somewhere, such as in memory or in a register, and not eliminate the input as dead code. This PR proposes to rename the method to `pretend_used`. This clearly indicates the precise semantics the hint conveys to the compiler, without suggesting that it disables further compiler optimizations. The name also reads straightforwardly in code: `hint::pretend_used(x)` hints to the compiler that it should pretend that `x` is used in some arbitrary way. `pretend_used` also rectifies the secondary naming concern the RFC raised with the names `black_box` and `bench_black_box`; the potential confusion with "boxed" values. If this change lands, it completes the naming portion of rust-lang#64102.
PR updated 👍 |
Re: lack of precedence, I actually think that's an advantage: "assume" is used in production code to enable optimizations by assuming something that is true, is true; "pretend" will be used in testing code to disable optimizations by pretending that something which is not actually true, is true. Suggested doc text: "An identity function that asks the compiler to pretend that a value is used in an arbitrary computation, usually to disable optimizations in benchmarking code." |
@LukasKalbertodt and @CryZe: your emoji reactions suggest that you did not like |
What about any (combination) of these, which all seem a lot less ambiguous (though maybe some may imply too much?):
|
Yeah, the problem we're grappling with is that this method really promises (or rather, hints) quite little. And exactly what the compiler is likely to do as a result is very compiler-dependent. In reality, all the method does is tell the compiler "consider this value as used in every conceivable, but legal way". No more, no less. What that means is up to the compiler. That's why I decided to propose the To use your proposals as examples:
I'm not quite sure I follow this — |
|
use std::mem::MaybeUninit; | ||
|
||
#[inline(never)] | ||
#[no_mangle] | ||
fn random() -> [isize; 32] { | ||
let r = unsafe { MaybeUninit::uninit().assume_init() }; | ||
// Avoid optimizing everything out. | ||
black_box(r) | ||
pretend_used(r) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pretend_use
/ blackbox / ... is the completely wrong function to call here right? It doesn't help with correctness and this whole code relies on the black box hiding the fact that it's UB to read uninitialized memory from the compiler. (Same in the address sanitizer test)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, I think what's going on here is actually that we want the code to be incorrect, but without pretend_used
(as the comment implies) the r
would be entirely optimized out by the compiler. pretend_used
here causes the compiler to leave r
in, which in turn means that the undefined behavior can be detected by the sanitizer.
Okay, I believe at this point I'm even more confused than before. My understanding of this function is that it's an identity function, but this is intentionally hidden from the compiler (though not guaranteed) to prevent the compiler from knowing it's an identity function, so the compiler can't assume anything about the value anymore, meaning that no constant folding can happen and any other assumptions the compiler made about the value are completely lost.
If it is (and it apparently is?) more subtle than that, then the current documentation (and name) do an incredibly bad job of conveying what kind of optimizations exactly are and are not posssible, i.e. using a value, what does that even mean to the user of this API, as someone who doesn't even know about internals of compiler optimizations. |
It definitely is a bit confusing. Part of the problem is that the actual semantics of the method really are "pretend that the program may have any legal Rust impl for this function". That does include things like constant folding (since it might return a different value than was provided) and dead code elimination (since the method could have side-effects), but it is not truly a black box in the way black box is normally defined in other contexts. @hanna-kruppe had a good summary over in #64102 (comment), and there's also @cramertj's original comment over in rust-lang/rfcs#2360 (comment). The concern is specifically, assuming I've understood them correctly, that if it is called I completely agree with you that the current documentation is inaccurate. I tried to make it slightly better in this PR, but it's difficult because the "meaning" of this function to the end user is so ill-defined. I definitely do not think the updated docs in this PR are sufficient, they were only meant to be a starting point for making progress on #64102. |
@jonhoo The prefix
Just as counter-example, I was thinking about a better word since yesterday, but didn't come up with anything useful. I guess
|
Hmm, yeah, I see what you mean. For Another take would be to go with something like |
Arbitrary impl could also be a no-op. In some sense, maybe "assume nothing" is what we want to get at -- i.e., the compiler should not presume that it knows anything about the function call being made and what it's effects are, beyond the normal "Rust guarantees" (i.e., mutable aliasing etc). But assume_nothing looks quite odd... |
@Mark-Simulacrum Another challenge with There's also a challenge here around the "object" of the verb that the function represents. |
Maybe we want |
Yeah, that might be a good idea. I prefer |
There's also the argument that because this is in the |
Here's a super weird suggestion: |
Here's a super weird suggestion: `std::hint::arbitrary_safe_code`.
A name like `mock_fn()` might help make it clear this is just meant for testing, not correctness.
|
True, though |
Another way might be |
Another way might be `pretend_arbitrarily_used`?
I gotta admit, seems kinda long. I'm personally OK if the exact details are
100% fully explained in the docs, which I'd expect anyone seeing "pretend_used"
for the first time to read at least once.
This is for test code remember, where the ratio of time spent writing the code
vs time spent reading it will be higher than the usual case where more time is
spent reading than writing.
|
I'm thinking about something like: fn pretend_modify<T>(v: &mut T); or even just fn touch<T>(v: &mut T); but this is a little too jargon-y, i think... |
fn pretend_modify<T>(v: &mut T); This probably isn't what we want, since As for the names, |
How about |
I'm not sure what Could you say more about what you think |
Just throwing a few more things out there:
I think I actually somewhat like // Hide constant
number_of_primes_below(hint::conceal_value(1000));
// Hide result of computation
vec.sort();
hint::conceal_value(vec); |
I think anything named "conceal", "hide" or similar will be confused with cryptography.
…On August 5, 2020 4:46:26 PM EDT, Lukas Kalbertodt ***@***.***> wrote:
Just throwing a few more things out there:
- `conceal`,
- `pretend_concealed`
- `conceal_value`
- `conceal_from_compiler`
- Or any of the above with `veil` instead of `conceal`
I think I actually somewhat like `conceal` and `conceal_value`. Seem fitting for both situations:
```rust
// Hide constant
number_of_primes_below(hint::conceal_value(1000));
// Hide result of computation
vec.sort();
hint::conceal_value(vec);
```
--
You are receiving this because you commented.
Reply to this email directly or view it on GitHub:
#74853 (comment)
|
Here's a different proposal: The idea is that it conveys to the compiler that it will consume the value that is passed to it, in some unspecified way. The |
Given there's no consensus here on the naming, I'm going to close this as this stage. I think we could discuss this in an issue or a MCP (once t-libs officially starts doing MCPs) and then rework this. Thanks :) |
EDIT (2020-07-29): Changed from
assume_used
topretend_used
following #74853 (comment)The current name is a legacy from before RFC 2360. The RFC calls the
method
bench_black_box
, though acknowledges that this name is not beideal either.
The main objection to the name during and since the RFC is that it is
not truly a black box to the compiler. Instead, the hint only encourages
the compiler to consider the passed-in value used. This in the hope that
the compiler will materialize that value somewhere, such as in memory or
in a register, and not eliminate the input as dead code.
This PR proposes to rename the method to
pretend_used
. This clearlyindicates the precise semantics the hint conveys to the compiler,
without suggesting that it disables further compiler optimizations. The
name also reads straightforwardly in code:
hint::pretend_used(x)
hintsto the compiler that it should pretend that
x
is used in somearbitrary way.
pretend_used
also rectifies the secondary naming concern the RFCraised with the names
black_box
andbench_black_box
; the potentialconfusion with "boxed" values.
If this change lands, it completes the naming portion of #64102.