diff --git a/kmir/src/kmir/kdist/mir-semantics/intrinsics.md b/kmir/src/kmir/kdist/mir-semantics/intrinsics.md index 5da5a85f2..8788d9861 100644 --- a/kmir/src/kmir/kdist/mir-semantics/intrinsics.md +++ b/kmir/src/kmir/kdist/mir-semantics/intrinsics.md @@ -143,6 +143,26 @@ write the value to that location. ... ``` +#### Volatile Load (`std::intrinsics::volatile_load`, `std::ptr::read_volatile`) + +The `volatile_load` intrinsic reads a value from a memory location through a pointer, ensuring the read is not +optimised away by the compiler. Unlike normal loads, volatile loads are guaranteed to occur exactly once and +in order with respect to other volatile operations. In the semantics, this is equivalent to a regular load +through a dereferenced pointer. We extract the place from the pointer operand, add a deref projection, and +read the value from that location into the destination. Since `#setLocalValue` is strict in its second argument, +the dereferenced operand is evaluated (i.e., the value is read from memory) before being written to `DEST`. + +```k + rule #execIntrinsic(IntrinsicFunction(symbol("volatile_load")), operandCopy(place(LOCAL, PROJ)) .Operands, DEST, _SPAN) + => #setLocalValue(DEST, operandCopy(place(LOCAL, appendP(PROJ, projectionElemDeref .ProjectionElems)))) + ... + + // for `operandMove` the pointer is moved, but the pointed-to value is copied (read, not consumed) + rule #execIntrinsic(IntrinsicFunction(symbol("volatile_load")), operandMove(place(LOCAL, PROJ)) .Operands, DEST, _SPAN) + => #setLocalValue(DEST, operandCopy(place(LOCAL, appendP(PROJ, projectionElemDeref .ProjectionElems)))) + ... +``` + #### Ptr Offset Computations (`std::intrinsics::ptr_offset_from`, `std::intrinsics::ptr_offset_from_unsigned`) The `ptr_offset_from[_unsigned]` calculates the distance between two pointers within the same allocation, diff --git a/kmir/src/tests/integration/data/prove-rs/read_volatile.rs b/kmir/src/tests/integration/data/prove-rs/read_volatile.rs new file mode 100644 index 000000000..1d8f96587 --- /dev/null +++ b/kmir/src/tests/integration/data/prove-rs/read_volatile.rs @@ -0,0 +1,11 @@ +fn main() { + let a: i32 = 5555; + let a_ptr = &a as *const _; + + let b: i32; + unsafe { + b = std::ptr::read_volatile(a_ptr); + } + + assert!(b == 5555); +} diff --git a/kmir/src/tests/integration/data/prove-rs/volatile_load.rs b/kmir/src/tests/integration/data/prove-rs/volatile_load.rs new file mode 100644 index 000000000..313adec3f --- /dev/null +++ b/kmir/src/tests/integration/data/prove-rs/volatile_load.rs @@ -0,0 +1,12 @@ +#![feature(core_intrinsics)] +fn main() { + let a: i32 = 5555; + let a_ptr = &a as *const _; + + let b: i32; + unsafe { + b = std::intrinsics::volatile_load(a_ptr); + } + + assert!(b == 5555); +}