When do we get loads/stores with volatile semantics (if we get them at all)?

Hello Haskell Friends, Recently I noticed some strange behavior in a program that uses peek/poke to manipulate memory mapped hardware registers, that smells a lot like missing volatile semantics to me. It hadn’t occurred to me that peek/poke might not have volatile semantics (they return an IO, and that IO has to happen, right?), but naturally once they’re lowered all such bets are off. This made me wonder: - Do we have a type like #Addr whose loads/stores have volatile semantics? - Do we have any primops with volatile semantics at all? - Are there any tricks one could use to get volatile semantics out of base’s peek/poke functions? Poking around, I’m afraid the answer to all three of these is “no.” If so, I’d be very interested in contributing volatile load/store primops and working out some way to make them easily available from Foreign.Storable. Does no such thing currently exist or am I missing something? Thanks for all your ongoing efforts, Travis

Hi Travis,
- Do we have a type like #Addr whose loads/stores have volatile semantics?
Nope
- Do we have any primops with volatile semantics at all?
We have atomicReadIntArray#, atomicWriteIntArray# prim ops, the
read/write on MutableByteArray# will introduce proper memory barriers.
However there's no Addr# equivalent yet.
- Are there any tricks one could use to get volatile semantics out of
base’s peek/poke functions?
It's always possible to write cbits for volatile load/store. To avoid
the overhead of unsafe foreign ccalls, the proper thing to do would be
to add primops, and lower them to MO_AtomicRead/MO_AtomicWrite at the
Cmm level.
Cheers,
Cheng
On Fri, Sep 9, 2022 at 7:14 PM Travis Whitaker
Hello Haskell Friends,
Recently I noticed some strange behavior in a program that uses peek/poke to manipulate memory mapped hardware registers, that smells a lot like missing volatile semantics to me. It hadn’t occurred to me that peek/poke might not have volatile semantics (they return an IO, and that IO has to happen, right?), but naturally once they’re lowered all such bets are off. This made me wonder:
- Do we have a type like #Addr whose loads/stores have volatile semantics?
- Do we have any primops with volatile semantics at all?
- Are there any tricks one could use to get volatile semantics out of base’s peek/poke functions?
Poking around, I’m afraid the answer to all three of these is “no.” If so, I’d be very interested in contributing volatile load/store primops and working out some way to make them easily available from Foreign.Storable. Does no such thing currently exist or am I missing something?
Thanks for all your ongoing efforts,
Travis _______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

Travis Whitaker
Hello Haskell Friends,
Recently I noticed some strange behavior in a program that uses peek/poke to manipulate memory mapped hardware registers, that smells a lot like missing volatile semantics to me. It hadn’t occurred to me that peek/poke might not have volatile semantics (they return an IO, and that IO has to happen, right?), but naturally once they’re lowered all such bets are off. This made me wonder:
- Do we have a type like #Addr whose loads/stores have volatile semantics?
We don't.
- Do we have any primops with volatile semantics at all?
I have in the past wanted to introduce acquire/release accesses in Cmm (instead of the arbitrary barriers that we use today), but I have never considered adding volatile. The semantics of the {read,write}*Addr# family of primops are a bit under-specified. However, I think you are right that it would be reasonable to assume them to have semantics similar to those of non-atomic access in C (or slightly stronger since we *do* guarantee that the access will actually reach memory such that it will be visible to a non-Haskell program eventually). I'd be interested in knowing more about your application is here. In general accessing memory mapped registers from user-space requires extreme care (typically with cooperation from the kernel since you need write-through physical memory mappings); volatile alone isn't sufficient. What concretely are you doing?
- Are there any tricks one could use to get volatile semantics out of base’s peek/poke functions?
I don't believe so. In your situation I would likely introduce a set of foreign functions which provides a volatile reads/writes. However, as noted above, just `volatile` alone won't be sufficient to guarantee robust access to memory-mapped registers.
Poking around, I’m afraid the answer to all three of these is “no.” If so, I’d be very interested in contributing volatile load/store primops and working out some way to make them easily available from Foreign.Storable. Does no such thing currently exist or am I missing something?
I think the first thing to ask is what you want from your "volatile" primops. I'd be somewhat reluctant to add a primops for memory mapped IO since, as noted above, "volatile" is only half of the story and the other half is highly platform dependent. However, I am happy to discuss. Cheers, - Ben
participants (3)
-
Ben Gamari
-
Cheng Shao
-
Travis Whitaker