What do you mean exactly by "behave differently on the other side of the cast”? Do you have a concrete example?
I was hesitant to say only in that it is probably an "abuse of mechanics" and definitely playing with fire, _however_ the target I'm working on has extensive bit operations for a subset of memory, including atomic test-and-set, etc. It's convenient to be able to pass around addresses of these bits, in particular for handling SFRs and interfacing with peripherals that require the use of these instructions. I know this could be handled with intrinsic functions (as with much in LLVM), however this removes the opportunity for globally allocating low cost atomic flags.
Modelled as address spaces, p0 and p<bit> would have different CHAR_BITs, of 8 and 1 respectively. This somewhat works as one would expect too, with, ((bit *)&somevalue) producing bit3 of somevalue - at least until the first time you access through a struct or array:
gep(addrspacecast(gep p0, 4) to p<bit>, 3) == (p0 + 4) * 8 + 3
As LLVM optimises this expression to:
addrspacecast(gep p0, 4 + 3) to p<bit>
Producing something entirely different.
But that said, I cannot think of a case where this would be a problem _except_ where CHAR_BIT would be different in one addrspace to the other, which LLVM doesn't claim to support AFAIK. Or somewhat generalised, where pX is a subset of pY, but pY has other addressable values between each valid pX in pY.
I note LLVM assumes that an address will load the same value regardless of what addrspace it is read from, which I understand as matching GPU behaviour well. I know some processors have different opcodes to retrieve/store high and low instruction words through the same pointer, which means they could not be modelled as separate addrspaces either, but rather requiring implicit functions to dereference - and this is likely to be the better way, to be fair.
My personal thoughts are that LLVM should not require these assumptions of GPU-style addrspace layouts, but offer a target hook to make addrspacecast a blackbox for gep and load/store combining. Or at least spell out somewhere exactly what the rules are on addrspacecast, which seems to be what's missing at the moment - is it something that can be used to describe a form of addressable memory, or is it formally required that they share the same byte size and that if an address is castable from one addrspace to another, that those values are strict aliases of one another.