I think more like a medium level language somewhere between assembly and C, with a clear distinction between a "virtual register bank" and "mass storage memory". Moving data between the two would be an explicit operation, not something the compiler would ever do automatically.
So, one way you can do this is to mark all your "memory" pointers as volatile, then load them into register variables and store them back manually. This would actually allow for very aggressive optimizations in the region that you've fenced off with "register" since the compiler can assume there is no aliasing, while letting you define the boundary where you'd like to writes to "go to the hardware". In C this might be a bit of boilerplate but in C++ once could assume you could RAII the boilerplate away…might be worth exploring.