Skip to content

Commit ff9d9a6

Browse files
authored
Implement Subslice projection and RawPtr aggregate value (#646)
* Aggregate kind `RawPtr` (`RValue`) takes two arguments, a pointer and metadata, and creates a new pointer. No test program (yet). * Subslice (`ProjectionElem`) : operates on arrays and slices, extracts a shorter (possibly empty) slice. Tested using a small program that matches the tail of a slice using `let [a, b, c, rest @ ..] = input_slice`. Both are required for the P-token proofs to progress. Also copied the description of all projections from the docs into the actual semantics.
1 parent 29b43ff commit ff9d9a6

File tree

2 files changed

+110
-0
lines changed

2 files changed

+110
-0
lines changed

kmir/src/kmir/kdist/mir-semantics/rt/data.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,29 @@ A variant `#forceSetLocal` is provided for setting the local value without check
211211

212212
### Traversing Projections for Reads and Writes
213213

214+
A `Place` to read from or write to is a `Local` variable (actually just its index), and a (potentially empty) vector of `ProjectionElem`ents.
215+
216+
There are different kinds of `ProjectionElem`s:
217+
- `Deref`erencing references or pointers (or `Box`es allocated in the heap)
218+
- read data at the address given in the local
219+
- operates on a value that is a pointer or reference to another
220+
- `Field` access in struct.s and tuples
221+
- fields are numbered from zero (in source order). The field type is also given.
222+
- operates on structs and tuples
223+
- `Index`ing into arrays or slices
224+
- operates on a value that is an array (statically-known size) or slice (variable size)
225+
- indexes zero-based from the front
226+
- the index is provided in another local
227+
- `ConstantIndex`ing with a constant offset
228+
- operates on a value that is an array (statically-known size) or slice (variable size)
229+
- the index was statically known and is therefore a `u64`
230+
- the `min_length` of the object to index into is provided as another `u64`
231+
- when `from_end` is true, this is taken to be exact, and indexing happens from the end
232+
- `Subslice`
233+
- a slice from `from` to `to` (the latter either from start or `from_end`)
234+
- operates on a value that is an array (statically-known size) or slice (variable size)
235+
- Casting values (`OpaqueCast` or `Downcast` - variant narrowing) and `Subtype`ing
236+
214237
Read and write operations to places that include (a chain of) projections are handled by a special rewrite symbol `#traverseProjection`.
215238
This helper does the projection lookup and maintains the context chain along the lookup path, then passes control back to `#readProjection` and `#writeProjection`/`#setMoved`.
216239
A `Deref` projection in the projections list changes the target of the write operation, while `Field` updates change the value that is being written (updating just one field of it), recursively.
@@ -278,6 +301,7 @@ These helpers mark down, as we traverse the projection, what `Place` we are curr
278301
// retains information about the value that was deconstructed by a projection
279302
syntax Context ::= CtxField( VariantIdx, List, Int )
280303
| CtxIndex( List , Int ) // array index constant or has been read before
304+
| CtxSubslice( List , Int , Int ) // start and end always counted from beginning
281305
282306
syntax Contexts ::= List{Context, ""}
283307
@@ -294,6 +318,12 @@ These helpers mark down, as we traverse the projection, what `Place` we are curr
294318
=> #buildUpdate(Range(ELEMS[I <- VAL]), CTXS)
295319
[preserves-definedness] // valid list indexing checked upon context construction
296320
321+
// we don't expect an update to happen on an entire _subslice_ but define a rule for it anyway
322+
rule #buildUpdate(Range(INNER), CtxSubslice(ELEMS, START, END) CTXS)
323+
=> #buildUpdate( Range(updateList(ELEMS, START, INNER)), CTXS)
324+
requires size(INNER) ==Int END -Int START // ensures updateList is defined
325+
[preserves-definedness] // START,END indexes checked before, length check for update here
326+
297327
syntax StackFrame ::= #updateStackLocal ( StackFrame, Int, Value ) [function]
298328
299329
rule #updateStackLocal(StackFrame(CALLER, DEST, TARGET, UNWIND, LOCALS), I, VAL)
@@ -460,6 +490,52 @@ In case of a `ConstantIndex`, the index is provided as an immediate value, toget
460490
rule #expectUsize(Integer(I, 64, false)) => I
461491
```
462492

493+
A `Subslice` projection operates on an array or slice (`Range`) value to extract a slice of the array from a start index to an end index (exclusive) [^subslice].
494+
Start and end index are given as immediate values.
495+
Similar to `ConstantIndex`, the slice _end_ index may count from the _end_ or the start of the array if flagged as such.
496+
497+
[^subslice]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/type.ProjectionKind.html#variant.Subslice
498+
499+
```k
500+
rule <k> #traverseProjection(
501+
DEST,
502+
Range(ELEMENTS),
503+
projectionElemSubslice(START, END, false) PROJS,
504+
CTXTS
505+
)
506+
=> #traverseProjection(
507+
DEST,
508+
Range(range(ELEMENTS, START, size(ELEMENTS) -Int END)),
509+
PROJS,
510+
CtxSubslice(ELEMENTS, START, END) CTXTS
511+
)
512+
...
513+
</k>
514+
requires 0 <=Int START andBool START <=Int size(ELEMENTS)
515+
andBool 0 <Int END andBool END <=Int size(ELEMENTS)
516+
andBool START <Int END
517+
[preserves-definedness] // Indexes checked to be in range for ELEMENTS
518+
519+
rule <k> #traverseProjection(
520+
DEST,
521+
Range(ELEMENTS),
522+
projectionElemSubslice(START, END, true) PROJS, // END from end of ELEMS
523+
CTXTS
524+
)
525+
=> #traverseProjection(
526+
DEST,
527+
Range(range(ELEMENTS, START, END)),
528+
PROJS,
529+
CtxSubslice(ELEMENTS, START, size(ELEMENTS) -Int END) CTXTS
530+
)
531+
...
532+
</k>
533+
requires 0 <=Int START andBool START <=Int size(ELEMENTS)
534+
andBool 0 <=Int END andBool END <Int size(ELEMENTS)
535+
andBool START <=Int size(ELEMENTS) -Int END
536+
[preserves-definedness] // Indexes checked to be in range for ELEMENTS
537+
```
538+
463539
#### References
464540

465541
A `Deref` projection operates on `Reference`s or pointers (`PtrLocal`) that refer to locals in the same or
@@ -725,6 +801,24 @@ Literal arrays are also built using this RValue.
725801
</k>
726802
```
727803

804+
The `AggregateKind::RawPtr`, somewhat as a special case of a `struct` aggregate, constructs a raw pointer
805+
from a given data pointer and metadata[^rawPtrAgg]. In case of a _thin_ pointer, the metadata is a unit value,
806+
for _fat_ pointers it is a `usize` value indicating the data length.
807+
808+
[^rawPtrAgg]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.AggregateKind.html#variant.RawPtr
809+
810+
```k
811+
rule <k> ListItem(PtrLocal(OFFSET, PLACE, _, _)) ListItem(Integer(LENGTH, 64, false)) ~> #mkAggregate(aggregateKindRawPtr(_TY, MUT))
812+
=> PtrLocal(OFFSET, PLACE, MUT, ptrEmulation(dynamicSize(LENGTH)))
813+
...
814+
</k>
815+
816+
rule <k> ListItem(PtrLocal(OFFSET, PLACE, _, _)) ListItem(Aggregate(_, .List)) ~> #mkAggregate(aggregateKindRawPtr(_TY, MUT))
817+
=> PtrLocal(OFFSET, PLACE, MUT, ptrEmulation(noMetadata))
818+
...
819+
</k>
820+
```
821+
728822
The `Aggregate` type carries a `VariantIdx` to distinguish the different variants for an `enum`.
729823
This variant index is used to look up the _discriminant_ from a table in the type metadata during evaluation of the `Rvalue::Discriminant`.
730824
Note that the discriminant may be different from the variant index for user-defined discriminants and uninhabited variants.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
fn main() {
2+
let a = [1,2,3u8];
3+
f(&a);
4+
let a = [4,5,6,7,8,9u8];
5+
f(&a);
6+
}
7+
8+
fn f(xs: &[u8]) {
9+
// let [a, b, c, rest @ ..] = xs
10+
// else { panic!("Need at least three elements"); };
11+
// println!("Array {xs:?} is ( {a}, {b}, {c}, {rest:?} )");
12+
13+
if let [a, b, c, rest @ ..] = xs {
14+
assert!(a + b - c == rest.len() as u8);
15+
}
16+
}

0 commit comments

Comments
 (0)