Your comment is incorrect as well.
The C specification describes semantics in terms of an abstract machine which is actually quite different from real hardware (most notably in terms of how memory works!). It then goes on to say that the compiler may choose to implement it radically differently, so long as the observable semantics (I/O calls and volatile accesses) are preserved. I'd have to double check whether it was C or C++ that said that the compiler is free to assume that infinite loops do not exist.
> Actually, you promise not to change things from another thread, DMA, interrupt handler, signal, etc, with any non-volatile reference passed, let alone a const!
This is not the case. The C specification requires that you use volatile to indicate that code outside of the C execution model may access the memory location. Of your list, only DMA and interrupt handlers are outside the execution model; signal handlers and threads are both considered inside the memory model. The only way for a signal handler to communicate with code outside the signal handler is with volatile sig_atomic_t; volatile int does not cut it. To communicate between threads, you need to ensure proper synchronization. This may involve the use of locks, fences, or atomics with appropriate orderings chosen.
> The compiler loads things into registers and has no way to know if memory in a passed reference changes underneath the hood
To be pedantic, the compiler relies on undefined behavior here. It is undefined behavior if you cause the value to be changed in a way that violates these rules, so the compiler has absolutely no restrictions on what may happen in such executions.
> If you've ever head about how "double check locking" is an antipattern, this is a big part of why.
This has absolutely nothing to do with why double-checked locking is incorrect. Double-checked locking is problematic in large part because of hardware reordering of loads and stores. In general, you need a store barrier to guarantee that all of the modifications the first thread changed has been made visible to other processors followed by a load barrier to guarantee that all prior modifications from other processors have been made visible to the second thread. Volatile does absolutely nothing to provide these barriers (except if you use MSVC, which documents that they treat volatile variables as equivalent to acquire/release semantics on x86 because regular loads and stores on x86 have those semantics anyways--this is nonportable behavior). The double-checked locking pattern does not provide a load barrier in the second thread, which means the ordering semantics are not guaranteed. If you use atomic loads and stores when implementing double-checked locking, you do get the necessary semantics for correctness.