@@ -4,8 +4,9 @@ This module addresses all aspects of handling "values" i.e., data, at runtime du
4
4
5
5
6
6
``` k
7
- requires "../ty.md"
8
7
requires "../body.md"
8
+ requires "../ty.md"
9
+ requires "./types.md"
9
10
requires "./value.md"
10
11
requires "./numbers.md"
11
12
@@ -23,6 +24,7 @@ module RT-DATA
23
24
24
25
imports RT-VALUE-SYNTAX
25
26
imports RT-NUMBERS
27
+ imports RT-TYPES
26
28
imports KMIR-CONFIGURATION
27
29
```
28
30
@@ -215,7 +217,7 @@ A `Deref` projection in the projections list changes the target of the write ope
215
217
These helpers mark down, as we traverse the projection, what ` Place ` we are currently looking up in the traversal.
216
218
` #buildUpdate ` helps to reconstruct the new value stored at that ` Place ` if we need to do a write (using the ` Context ` built during traversal).
217
219
218
- ``` k
220
+ ``` k
219
221
// stores the target of the write operation, which may change when references are dereferenced.
220
222
syntax WriteTo ::= toLocal ( Int )
221
223
| toStack ( Int , Local )
@@ -271,6 +273,8 @@ These helpers mark down, as we traverse the projection, what `Place` we are curr
271
273
272
274
rule #adjustRef(typedValue(Reference(HEIGHT, PLACE, REFMUT), TY, MUT), OFFSET)
273
275
=> typedValue(Reference(HEIGHT +Int OFFSET, PLACE, REFMUT), TY, MUT)
276
+ rule #adjustRef(typedValue(PtrLocal(HEIGHT, PLACE, REFMUT), TY, MUT), OFFSET)
277
+ => typedValue(PtrLocal(HEIGHT +Int OFFSET, PLACE, REFMUT), TY, MUT)
274
278
rule #adjustRef(TL, _) => TL [owise]
275
279
276
280
rule #incrementRef(TL) => #adjustRef(TL, 1)
@@ -438,6 +442,45 @@ In the simplest case, the reference refers to a local in the same stack frame (h
438
442
requires OFFSET ==Int 0
439
443
andBool 0 <=Int I andBool I <Int size(LOCALS)
440
444
[preserves-definedness]
445
+
446
+
447
+ rule <k> #traverseProjection(
448
+ _DEST,
449
+ typedValue(PtrLocal(OFFSET, place(LOCAL, PLACEPROJ), _MUT), _, _),
450
+ projectionElemDeref PROJS,
451
+ _CTXTS
452
+ )
453
+ => #traverseProjection(
454
+ toStack(OFFSET, LOCAL),
455
+ #localFromFrame({STACK[OFFSET -Int 1]}:>StackFrame, LOCAL, OFFSET),
456
+ appendP(PLACEPROJ, PROJS), // apply reference projections first, then rest
457
+ .Contexts // previous contexts obsolete
458
+ )
459
+ ...
460
+ </k>
461
+ <stack> STACK </stack>
462
+ requires 0 <Int OFFSET andBool OFFSET <=Int size(STACK)
463
+ andBool isStackFrame(STACK[OFFSET -Int 1])
464
+ [preserves-definedness]
465
+
466
+ rule <k> #traverseProjection(
467
+ _DEST,
468
+ typedValue(PtrLocal(OFFSET, place(local(I), PLACEPROJ), _MUT), _, _),
469
+ projectionElemDeref PROJS,
470
+ _CTXTS
471
+ )
472
+ => #traverseProjection(
473
+ toLocal(I),
474
+ {LOCALS[I]}:>TypedLocal,
475
+ appendP(PLACEPROJ, PROJS), // apply reference projections first, then rest
476
+ .Contexts // previous contexts obsolete
477
+ )
478
+ ...
479
+ </k>
480
+ <locals> LOCALS </locals>
481
+ requires OFFSET ==Int 0
482
+ andBool 0 <=Int I andBool I <Int size(LOCALS)
483
+ [preserves-definedness]
441
484
```
442
485
443
486
## Evaluation of R-Values (` Rvalue ` sort)
@@ -533,6 +576,8 @@ For tuples and `struct`s, this index is always 0.
533
576
Tuples, ` struct ` s, and ` enum ` s are built as ` Aggregate ` values with a list of argument values.
534
577
For ` enums ` , the ` VariantIdx ` is set, and for ` struct ` s and ` enum ` s, the type ID (` Ty ` ) is retrieved from a special mapping of ` AdtDef ` to ` Ty ` .
535
578
579
+ Literal arrays are also built using this RValue.
580
+
536
581
``` k
537
582
rule <k> rvalueAggregate(KIND, ARGS) => #readOperands(ARGS) ~> #mkAggregate(KIND) ... </k>
538
583
@@ -547,12 +592,18 @@ For `enums`, the `VariantIdx` is set, and for `struct`s and `enum`s, the type ID
547
592
<adt-to-ty> ADTMAPPING </adt-to-ty>
548
593
requires isTy(ADTMAPPING[ADTDEF])
549
594
550
- rule <k> ARGS:List ~> #mkAggregate(_OTHERKIND)
595
+ rule <k> ARGS:List ~> #mkAggregate(aggregateKindArray(_TY))
596
+ =>
597
+ typedValue(Range(ARGS), TyUnknown, mutabilityNot)
598
+ ...
599
+ </k>
600
+
601
+
602
+ rule <k> ARGS:List ~> #mkAggregate(aggregateKindTuple)
551
603
=>
552
604
typedValue(Aggregate(variantIdx(0), ARGS), TyUnknown, mutabilityNot)
553
605
...
554
606
</k>
555
- [owise]
556
607
557
608
558
609
// #readOperands accumulates a list of `TypedLocal` values from operands
@@ -640,23 +691,71 @@ A `CopyForDeref` `RValue` has the semantics of a simple `Use(operandCopy(...))`,
640
691
641
692
``` k
642
693
rule <k> rvalueCopyForDeref(PLACE) => rvalueUse(operandCopy(PLACE)) ... </k>
694
+ ```
695
+
696
+ The ` RValue::AddressOf ` operation is very similar to creating a reference, since it also
697
+ refers to a given _ place_ . However, the raw pointer obtained by ` AddressOf ` can be subject
698
+ to casts and pointer arithmetic using ` BinOp::Offset ` .
643
699
644
- // AddressOf: not implemented yet
700
+ ``` k
701
+ rule <k> rvalueAddressOf(MUT, PLACE)
702
+ =>
703
+ typedValue(PtrLocal(0, PLACE, MUT), TyUnknown, MUT)
704
+ // we should use #alignOf to emulate the address
705
+ ...
706
+ </k>
707
+ ```
708
+
709
+ In practice, the ` AddressOf ` can often be found applied to references that get dereferenced first,
710
+ turning a borrowed value into a raw pointer. To shorten out chains of Deref and AddressOf/Reference,
711
+ a special rule for this case is applied with higher priority.
712
+
713
+ ``` k
714
+ rule <k> rvalueAddressOf(MUT, place(local(I), projectionElemDeref .ProjectionElems))
715
+ =>
716
+ typedValue(refToPtrLocal({LOCALS[I]}:>TypedValue), TyUnknown, MUT)
717
+ // we should use #alignOf to emulate the address
718
+ ...
719
+ </k>
720
+ <locals> LOCALS </locals>
721
+ requires 0 <=Int I
722
+ andBool I <Int size(LOCALS)
723
+ andBool isTypedValue(LOCALS[I])
724
+ andBool isRef({LOCALS[I]}:>TypedValue)
725
+ [priority(40), preserves-definedness] // valid indexing checked, toPtrLocal can convert the reference
726
+
727
+ syntax Bool ::= isRef ( TypedValue ) [function, total]
728
+ // -----------------------------------------------------
729
+ rule isRef(typedValue(Reference(_, _, _), _, _)) => true
730
+ rule isRef( _OTHER ) => false [owise]
731
+
732
+ syntax Value ::= refToPtrLocal ( TypedValue ) [function]
733
+
734
+ rule refToPtrLocal(typedValue(Reference(OFFSET, PLACE, MUT), _, _)) => PtrLocal(OFFSET, PLACE, MUT)
645
735
```
646
736
647
737
## Type casts
648
738
649
739
Type casts between a number of different types exist in MIR.
650
- We implement a type cast from a ` TypedLocal ` to another when it is followed by a ` #cast ` item, rewriting ` typedLocal(...) ~> #cast(...) ~> REST ` to ` typedLocal(...) ~> REST ` .
651
740
652
741
``` k
653
742
syntax Evaluation ::= #cast( Evaluation, CastKind, Ty ) [strict(1)]
654
743
```
655
744
656
- ### Integer Type Casts
745
+ ### Number Type Casts
746
+
747
+ The simplest case of a cast is conversion from one number type to another:
657
748
658
- Casts between signed and unsigned integral numbers of different width exist, with a truncating semantics.
659
- These casts can only operate on the ` Integer ` variant of the ` Value ` type, adjusting bit width, signedness, and possibly truncating or 2s-complementing the value.
749
+ | CastKind |
750
+ | --------------|
751
+ | IntToInt |
752
+ | FloatToInt |
753
+ | FloatToFloat |
754
+ | IntToFloat |
755
+
756
+ ` IntToInt ` casts between signed and unsigned integral numbers of different width exist, with a
757
+ truncating semantics. These casts can only operate on the ` Integer ` variant of the ` Value ` type, adjusting
758
+ bit width, signedness, and possibly truncating or 2s-complementing the value.
660
759
661
760
``` k
662
761
// int casts
@@ -670,6 +769,63 @@ These casts can only operate on the `Integer` variant of the `Value` type, adjus
670
769
[preserves-definedness] // ensures #numTypeOf is defined
671
770
```
672
771
772
+ Casts involving ` Float ` values are currently not implemented.
773
+
774
+ ### Casts between pointer types
775
+
776
+
777
+ | CastKind | Description |
778
+ | ----------| ------------------------------------------------------------|
779
+ | PtrToPtr | Convert between references when representations compatible |
780
+
781
+ Pointers can be converted from one type to another (` PtrToPtr ` ) when the representations are compatible.
782
+ The compatibility of types (defined in ` rt/types.md ` ) considers their representations (recursively) in
783
+ the ` Value ` sort.
784
+ Conversion is especially possible for the case of _ Slices_ (of dynamic length) and _ Arrays_ (of static length),
785
+ which have the same representation ` Value::Range ` .
786
+
787
+ ``` k
788
+ rule <k> #cast(typedValue(VALUE, TY1, MUT), castKindPtrToPtr, TY2)
789
+ =>
790
+ typedValue(VALUE, TY2, MUT)
791
+ ...
792
+ </k>
793
+ <types> TYPEMAP </types>
794
+ requires #typesCompatible({TYPEMAP[TY1]}:>TypeInfo, {TYPEMAP[TY2]}:>TypeInfo, TYPEMAP)
795
+ ```
796
+
797
+ ` PointerCoercion ` may achieve a simmilar effect, or deal with function and closure pointers, depending on the coercion type:
798
+
799
+ | CastKind | PointerCoercion | Description |
800
+ | ------------------------------------| --------------------------| ----------------------- |
801
+ | PointerCoercion(_ , CoercionSource) | ArrayToPointer | from ` *const [T; N] ` to ` *const T ` |
802
+ | | Unsize | drop size information |
803
+ | | ReifyFnPointer | |
804
+ | | UnsafeFnPointer | |
805
+ | | ClosureFnPointer(Safety) | |
806
+ | | DynStar | create a dyn* object |
807
+ | | MutToConstPointer | make a mutable pointer immutable |
808
+
809
+
810
+ ``` k
811
+ // not checking whether types are actually compatible (trusting the compiler)
812
+ rule <k> #cast(typedValue(VALUE, _TY, MUT), castKindPointerCoercion(pointerCoercionUnsize), TY)
813
+ =>
814
+ typedValue(VALUE, TY, MUT)
815
+ ...
816
+ </k>
817
+ ```
818
+
819
+ ### Other casts involving pointers
820
+
821
+ | CastKind | Description |
822
+ | ------------------------------| -------------|
823
+ | PointerExposeProvenance | |
824
+ | PointerWithExposedProvenance | |
825
+ | FnPtrToPtr | |
826
+ | Transmute | |
827
+
828
+
673
829
## Decoding constants from their bytes representation to values
674
830
675
831
The ` Value ` sort above operates at a higher level than the bytes representation found in the MIR syntax for constant values.
@@ -699,7 +855,7 @@ This is currently only defined for `PrimitiveType`s (primitive types in MIR).
699
855
[preserves-definedness]
700
856
701
857
// zero-sized struct types
702
- rule <k> #decodeConstant(constantKindZeroSized, TY, typeInfoStructType(_, _))
858
+ rule <k> #decodeConstant(constantKindZeroSized, TY, typeInfoStructType(_, _, _ ))
703
859
=> typedValue(Aggregate(variantIdx(0), .List), TY, mutabilityNot) ... </k>
704
860
705
861
// TODO Char type
0 commit comments