I would highlight `std::launder` as an example. It was added in C++17. Famously, most people have no idea what it is used for or why it exists. For low-level systems it was a godsend because there wasn’t an official way to express the intent, though compilers left backdoors open because some things require it.
It generates no code, it is a compiler barrier related to constant folding and lifetime analysis that is particularly useful when operating on objects in DMA memory. As far as a compiler is concerned DMA doesn’t exist, it is a Deus Ex Machina. This is an annotation to the compiler that everything it thinks it understands about the contents and lifetime of a bit of memory is now voided and it has to start over. This case is endemic in high-end database engines.
It should be noted that `std::launder` only works for different instances of the same type. If you want to dynamically re-type memory there is a different set of APIs for informing the compiler that DMA dropped a completely different type in the same memory address.
All of this is compiled down to nothing. It annotates for the compiler things it can’t understand just by inspecting the code.
One thing that I've found really useful is being able to annotate o pointer's alignment. I'm working on an interpreter, and I'm using tagged pointers (6 bits), so the data structure needs to have 128 byte alignment. I can define a function like `fn toInt(ptr: *align(128) LongString) u56` and the compiler will track and enforce the alignment.
You might also find some of the builtin functions interesting as well[1], they have a lot of really useful functions that in other languages are only accessible via the blessed stdlib, such as @addrSpaceCast, @atomicLoad, @branchHint, @fieldParentPtr, @frameAddress, @prefetch, @returnAddress(), and more.
I don't think that's quite right. For DMA you would normally use an empty asm block, which is what's typically referred to as a "compiler barrier" and does tell the compiler to discard everything it knows about the contents of a some memory. But std::launder doesn't have the same effect. It only affects type-based optimizations, mainly aliasing, plus the assumption that an object's const fields and vtable can't change.
GCC generates a store followed by a load from the same location, because of the asm block (compiler barrier) in between. But if you change `if (1)` to `if (0)`, making it use `std::launder` instead of an asm block, GCC doesn't generate a load. GCC still assumes that the value read back from the pointer must be 42, despite the use of `std::launder`.
This doesn't seem quite right. The asm block case is equivalent to adding a volatile qualifier to the pointer. If you add this qualifier then `std::launder` produces the same codegen.
I think the subtle semantic distinction is that `volatile` is a current property of the type whereas `std::launder` only indicates that it was a former property not visible in the current scope. Within the scope of that trivial function in which the pointer is not volatile, the behavior of `std::launder` is what I'd expect. The practical effect is to limit value propagation of types marked `const` in that memory. Or at least this is my understanding.
DMA memory (and a type residing therein) is often only operationally volatile within narrow, controlled windows of time. The rest of the time you really don't want that volatile qualifier to follow those types around the code.