clang -O3 on linux amd64. I'm told that aliasing is unrelated to equality, and I guess the trick is that realloc's returned pointer is attributed noalias. I get assembly that does the check, does the stores, but omits the loads:
Omitting the loads doesn't mean it thinks the pointer is invalid, it just means it thinks the pointer doesn't alias. If it doesn't alias, and it's not volatile, then it can assume that what it just stored is what it would get by loading, so it can skip the load.
I guess the only difference between what you described and what I'm seeing is my clang recognizes that since p == q, then a store to one will overwrite the store to the other, and therefore it can skip storing the 1 and it can assuming reading both will return 2.