Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The one who is mistaken here is you, although I shouldn't be surprised that someone can dismiss what is relatively deep semantics work in compilers on the basis of misunderstanding what's actually going on.

The first fundamental issue is that pointer provenance is an area where people have (historically) dealt with the issue as essentially a requirement of data-dependency: for a dereference `p` to access an object x, then p must be at the end of a chain of arithmetic computations where &x is one of the inputs. It turns out, however, that compilers do not preserve data dependency, and there is pretty unanimous agreement among compiler writers and specification writers that they should not* do so in general.

What this means is that the challenge we have is how to specify something that generally follows the data-dependent rules while still allowing compilers to do their non-data-dependency-preserving optimizations. There is a working group in the C committee that is doing this. The current leading candidate for a specification is based on the idea that you track provenance (i.e., data dependency) via pointers, but not via integers.

This means that now we need to pin down what the actual semantics are where you convert a pointer to an integer or vice versa, and this blog post is part of the effort of trying to pin down sane semantics here.

So, yes, restrict is a promise from the programmer to the compiler... but what is the programmer actually promising? That's what this blog post is exploring.



> The one who is mistaken here is you, although I shouldn't be surprised that someone can dismiss [...]

Yes, I was mistaken in my first read through. I'm taking your indignation with some amusement, but I hope you can be civil going forward.

If you look at the second snippet of code, you can clearly see how it declares the arguments `restrict` and then uses them to access the same piece of memory. That's *wrong* - it violated the promise made by `restrict`.

What I didn't see at first was that the first snippet of code appears to be fine. As far as I can tell, it doesn't break any rules. *So the optimization pass from the first version to the second version is incorrect.* After that, everything that follows is still questionable.

The following passes use the `restrict` promise from the second version to eliminate from the load from `x` and so on...


You just fully agreed with what I said in the post. :) Explaining that one of the optimizations is wrong is my entire point. Then I go on saying which optimization is wrong (in my view) and propose a structural explanation for why it is wrong (casts have side-effects). Basically: if casts did not have side-effects, the optimization would be correct (it is always okay to remove a side-effect-free operation whose result is unused), so via proof by contradiction casts must have side-effects.


No, I don't agree with what you said in your post, and you make a lot of invalid proofs by contradiction.

The first pass of your optimizer took a valid program and made an invalid one. That should be the end of the article, but then you ran further (presumably valid) optimization passes which led to erroneous results.

Your whole argument seems to look like:

    (pointer_integer_pointer & invalidly_keeping_restrict) => erroneous_optimization
Since we can't have erroneous optimizations, you make a faulty conclusion the problem is pointer to integer round trips. You even say it here:

> However, the only possibly suspicious part of the original program is a pointer-integer-pointer round-trip

But it's not the only suspicious part, so all of your following statements are questionable. The contradiction should've led you to:

    !erroneous_optimization => (!pointer_integer_pointer | !invalidly_keeping_restrict)
Using Modus Tollens and De Morgan's. Instead you declare that casts have side-effects, dive into "integer provenance", make some distinction between "as" casts and transmute, and so on. Meanwhile, I conclude that broken optimizer passes should be fixed or removed.

> I would argue that the alternative is to treat the original program (after translation to Rust) as having Undefined Behavior.

I'm sure you'll get your way, and you probably won't stop until Rust has as many tricky "undefined behaviors" for the compiler to exploit as they do in C. Programmers will need a masters degree in "provenance" to avoid the traps you set for them. Then when they stumble and fall in the pit you dug, they can go to the forums and be chastised by the experts. You'll get some .1% speedup on a non-realistic benchmark and declare it a job well done.

> There are, to my knowledge, generally two reasons why people might want to transmute a pointer to an integer

This "argument by lack of imagination" strategy isn't sound either. What if you just haven't thought of a third reason yet?

> I think we should move towards discouraging, deprecating, or even entirely disallowing pointer-integer transmutation in Rust. That means a cast is the only legal way to turn a pointer into an integer

It's really unclear to me why the compiler can't recognize that transmuting a pointer to an integer is the same as a cast. And if it can recognize that, why make it UB?!? Maybe this is all about those 129 bit CHERI pointers. If you want to break the compiler for just that platform, more power to you.

Really, I don't care if you break transmute, so long you leave a way to cast function pointers:

https://rust-lang.github.io/unsafe-code-guidelines/layout/fu...




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: