@@ -10,7 +10,6 @@ requires "./types.md"
1010requires "./value.md"
1111requires "./numbers.md"
1212requires "./decoding.md"
13- requires "./pointer-int.md" // pointer/int encoding helpers live separately for readability
1413
1514module RT-DATA
1615 imports INT
@@ -28,7 +27,6 @@ module RT-DATA
2827 imports RT-NUMBERS
2928 imports RT-DECODING
3029 imports RT-TYPES
31- imports RT-POINTER-INT // shared pointer/int encoding + decoding helpers
3230 imports KMIR-CONFIGURATION
3331
3432```
@@ -318,6 +316,8 @@ These helpers mark down, as we traverse the projection, what `Place` we are curr
318316 | CtxSubslice( List , Int , Int ) // start and end always counted from beginning
319317 | CtxPointerOffset( List, Int, Int ) // pointer offset for accessing elements with an offset (Offset, Origin Length)
320318
319+ syntax ProjectionElem ::= PointerOffset( Int, Int ) // Same as subslice but coming from BinopOffset injected by us
320+
321321 syntax Contexts ::= List{Context, ""}
322322
323323 syntax Value ::= #buildUpdate ( Value , Contexts ) [function]
@@ -1456,6 +1456,45 @@ What can be supported without additional layout consideration is trivial casts b
14561456 requires lookupTy(TY_SOURCE) ==K lookupTy(TY_TARGET)
14571457```
14581458
1459+ Transmuting a pointer to an integer discards provenance and reinterprets the pointer’s offset as a value of the target integer type.
1460+
1461+ ``` k
1462+ syntax Int ::= #ptrOffsetBytes ( Int , MaybeTy ) [function, total]
1463+ rule #ptrOffsetBytes(PTR_OFFSET, _TY:Ty) => 0
1464+ requires PTR_OFFSET ==Int 0
1465+ rule #ptrOffsetBytes(PTR_OFFSET, TY:Ty)
1466+ => PTR_OFFSET *Int #elemSize(#lookupMaybeTy(elemTy(lookupTy(TY))))
1467+ requires PTR_OFFSET =/=Int 0
1468+ andBool #isUnsizedArrayType(lookupTy(TY))
1469+ rule #ptrOffsetBytes(_, _) => -1 [owise] // should not happen
1470+
1471+ syntax Bool ::= #isUnsizedArrayType ( TypeInfo ) [function, total]
1472+ rule #isUnsizedArrayType(typeInfoArrayType(_, noTyConst)) => true
1473+ rule #isUnsizedArrayType(_) => false [owise]
1474+ ```
1475+
1476+ ``` k
1477+ rule <k> #cast(
1478+ PtrLocal(_, _, _, metadata(_, PTR_OFFSET, _)),
1479+ castKindTransmute,
1480+ TY_SOURCE,
1481+ TY_TARGET
1482+ )
1483+ =>
1484+ #intAsType(
1485+ #ptrOffsetBytes(
1486+ PTR_OFFSET,
1487+ pointeeTy(#lookupMaybeTy(TY_SOURCE))
1488+ ),
1489+ #bitWidth(#numTypeOf(lookupTy(TY_TARGET))),
1490+ #numTypeOf(lookupTy(TY_TARGET))
1491+ )
1492+ ...
1493+ </k>
1494+ requires #isIntType(lookupTy(TY_TARGET))
1495+ andBool 0 <=Int #ptrOffsetBytes(PTR_OFFSET,pointeeTy(#lookupMaybeTy(TY_SOURCE)))
1496+ ```
1497+
14591498Other ` Transmute ` casts that can be resolved are round-trip casts from type A to type B and then directly back from B to A.
14601499The first cast is reified as a ` thunk ` , the second one resolves it and eliminates the ` thunk ` :
14611500
@@ -1560,56 +1599,6 @@ Casting an integer to a `[u8; N]` array materialises its little-endian bytes.
15601599 rule #staticArrayLenBits(_OTHER) => 0 [owise]
15611600```
15621601
1563- Transmuting a raw pointer to an integer (and back) uses the reversible encoding defined in ` RT-POINTER-INT ` .
1564- Keeping these helpers in a dedicated module keeps this file focused on semantics while still reusing the canonical encoding.
1565- The encoding serialises the pointer provenance, its place/projection, mutability and metadata into a natural number;
1566- decoding rehydrates the pointer metadata and reinterprets the byte offset for the target pointee type.
1567-
1568- ``` k
1569- syntax Value ::= #ptrWithOffset ( Value , Int , TypeInfo ) [function, total]
1570- rule #ptrWithOffset(PtrLocal(STACK, PLACE, MUT, metadata(SIZE, _, ORIGIN)), OFFSET, TYINFO)
1571- => PtrLocal(STACK, PLACE, MUT, #convertMetadata(metadata(SIZE, OFFSET, ORIGIN), TYINFO))
1572- rule #ptrWithOffset(VAL:Value, _, _) => VAL [owise]
1573- ```
1574-
1575- ``` k
1576- rule <k> #cast(
1577- PtrLocal(_, _, _, _) #as PTR,
1578- castKindTransmute,
1579- TY_SOURCE,
1580- TY_TARGET
1581- )
1582- =>
1583- #ptrIntValue(
1584- #encodePtrInt(PTR, pointeeTy(lookupTy(TY_SOURCE))), // full Cantor encoding
1585- #numTypeOf(lookupTy(TY_TARGET)) // signedness + width
1586- )
1587- ...
1588- </k>
1589- requires #isIntType(lookupTy(TY_TARGET))
1590- andBool pointeeTy(lookupTy(TY_SOURCE)) =/=K TyUnknown
1591-
1592- rule <k> #cast(
1593- Integer(VAL, WIDTH, SIGNED) #as _INT,
1594- castKindTransmute,
1595- TY_SOURCE,
1596- TY_TARGET
1597- )
1598- =>
1599- #ptrWithOffset(
1600- #decodePtrBase(#cantorUnpairLeft(#unsignedFromIntValue(VAL, WIDTH, SIGNED))),
1601- #bytesToPtrOffset(
1602- #cantorUnpairRight(#unsignedFromIntValue(VAL, WIDTH, SIGNED)),
1603- pointeeTy(lookupTy(TY_TARGET))
1604- ),
1605- lookupTy(TY_TARGET)
1606- )
1607- ...
1608- </k>
1609- requires #isIntType(lookupTy(TY_SOURCE))
1610- andBool pointeeTy(lookupTy(TY_TARGET)) =/=K TyUnknown
1611- ```
1612-
16131602A transmutation from an integer to an enum is wellformed if:
16141603- The bit width of the incoming integer is the same as the discriminant type of the enum
16151604 (e.g. ` u8 -> i8 ` fine, ` u8 -> u16 ` not fine) - this is guaranteed by the compiler;
@@ -2225,7 +2214,7 @@ A trivial case where `binOpOffset` applies an offset of `0` is added with higher
22252214 _CHECKED)
22262215 =>
22272216 PtrLocal( STACK_DEPTH , PLACE , MUT, metadata(CURRENT_SIZE, CURRENT_OFFSET +Int OFFSET_VAL, staticSize(ORIGIN_SIZE)) )
2228- requires OFFSET_VAL >=Int 0
2217+ requires OFFSET_VAL >=Int 0
22292218 andBool CURRENT_OFFSET +Int OFFSET_VAL <=Int ORIGIN_SIZE
22302219 [preserves-definedness]
22312220```
0 commit comments