Does LLVM assume that optimizations cannot be partially freed?

With code like this

%1 = load i64, ptr %ptr, align 4
tail call void @unk(ptr noundef nonnull %ptr)
%2 = load i32, ptr %ptr, align 4

will LLVM assume that after this code, ptr is dereferenceable for 8 bytes? It is clearly dereferenceable for 8 bytes before the call to unk, and if there is no such thing as partial deallocation, then that must carry over to after the call (since full deallocation would make the 2nd load UB).

I am asking because in Rust, the idea of a shrink_in_place operation for allocators has been floated, which would tell the allocator that some memory at the tail of an allocation is no longer needed. The difference to realloc is that all existing pointers to the allocation are guaranteed to remain valid. If unk performed such a shrink_in_place, then the assumption that ptr is dereferenceable for 8 bytes after the call definitely does not hold up. I’d like to know if there are any issues from the LLVM side with having such a partial deallocation API.

LLVM’s current memory model doesn’t allow changing the size of objects. realloc is modeled as creating a new object.

You want an in-place realloc. That sounds ok, but probably needs a new attribute like `no_inplace_realloc´ or whatever, that clang can place in all functions and Rust skips.

That would however still be a potential footgun when linking C code and Rust code.

AFAIK, nothing in the C standard says in-place realloc does not exist. Of course also nothing says that it does exist so it’s unclear as usual whether such a thing can be done in C or not…

One can totally already write such code, by munaping just a few pages at the end of an existing large mapping.

Isn’t it UB in C to use original pointer after it’s been realloc’ed even if it was done in-place? Not sure how else you are supposed to achieve that in standards-compliant way.

Yes, that is UB in C. But an allocator could expose an operation like realloc_in_place that guarantees to remain in-place and guarantees to keep the old pointers valid. That can be quite useful when a buffer has been shrunk and we want to give back that memory to the OS, without having to re-derive all our pointers.

Just because C can’t express this doesn’t mean it should never be done in any program written in any language that uses LLVM as its backend.