There seems to be some confusion in this thread about what LLVM actually does. You can see the attributes being applied to library functions here:
http://llvm.org/docs/doxygen/html/FunctionAttrs_8cpp_source.html
The only relevant one is malloc
's noalias, which means that alias analysis can assume that pointers it returns don't alias with anything else.
In particular, there is nothing special on free
. While the C standard would allow LLVM to turn the argument to a free
call into undef afterwards, it doesn't actually do so, presumably because this wouldn't be a useful optimization on any real programs - rather, the standard clause in question is a standardsese attempt to justify the alias optimization. This could theoretically change but I wouldn't hold my breath.
As for noalias -
This would mean, for example, that even though LLVM assumes p and q in my example not to alias, it would not be allowed to optimize p == q or p != q away into a constant. it would have to always preserve the original check. Is that the case?
Glancing at the LLVM code, and checking by looking at assembly output, it seems like that is currently the case, but said optimization sounds more like something that could hypothetically be added in the future, as one could imagine it being useful to remove redundant pointer equality checks in inlined functions or whatever. I certainly don't see any language in the definition of noalias
suggesting it would be out of bounds.
However, were LLVM to add such an optimization, I believe Rust would have no choice but to disable it: the optimizer is pretty powerful, so if there is any situation where safe code can trick it into assuming something that can turn out to be false, it is likely possible to get it to mistakenly eliminate bounds checks or whatnot with enough contortions. (As mentioned, you can certainly do that with undef
, though that isn't the issue here.)
(If you intend to test anything, note that noalias is inherently applied only to the C malloc function itself. AFAIK, LLVM can propagate noalias towards callers all the way to Box::new
, but only if it actually sees the whole chain, and only if the C malloc function is actually being used. The former requires LTO, and the latter requires using the system allocator rather than jemalloc directly, so you will have to compile with both to possibly notice a difference.
Alternately there may be something I don't know about that disables this functionality entirely for Rust, but I don't think so..)