Skip to content

Commit 7d1807d

Browse files
authored
Better discriminant types, transmute special cases, onInt attributes (#778)
* The `rvalueDiscriminant` operation was unconditionally returning 128-bit integers, which turns out to be wrong. We now consult the layout to return the correct bit width (but still always unsigned as this seems to be an invariant). Closes runtimeverification/solana-token#41 * Two special cases of `transmute` are implemented, removing `thunk`s that `transmute` would have created before. - round-trip `transmute`s through a given type back to the original type are eliminated - for a `transmute` from an `Integer` to an `enum` without fields followed by a `discriminant` operation, the original integer value is returned as the discriminant. * the (partial) `onInt` function was missing `preserves-definedness` attributes on its equation so booster did not apply it
1 parent 9e91328 commit 7d1807d

File tree

2 files changed

+68
-12
lines changed
  • kmir/src

2 files changed

+68
-12
lines changed

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

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,9 +1015,10 @@ The `getTyOf` helper applies the projections from the `Place` to determine the `
10151015
syntax Evaluation ::= #discriminant ( Evaluation , MaybeTy ) [strict(1)]
10161016
// ----------------------------------------------------------------
10171017
rule <k> #discriminant(Aggregate(IDX, _), TY:Ty)
1018-
=> Integer(#lookupDiscriminant(lookupTy(TY), IDX), 128, false) // parameters for stored u128
1018+
=> Integer(#lookupDiscriminant(lookupTy(TY), IDX), #discriminantSize(lookupTy(TY)), false)
10191019
...
10201020
</k>
1021+
requires #discriminantSize(lookupTy(TY)) =/=Int 0
10211022
10221023
syntax Int ::= #lookupDiscriminant ( TypeInfo , VariantIdx ) [function, total]
10231024
| #lookupDiscrAux ( Discriminants , Int ) [function]
@@ -1028,6 +1029,27 @@ The `getTyOf` helper applies the projections from the `Place` to determine the `
10281029
// --------------------------------------------------------------------
10291030
rule #lookupDiscrAux( discriminant(RESULT) _ , IDX) => RESULT requires IDX ==Int 0
10301031
rule #lookupDiscrAux( _:Discriminant MORE:Discriminants, IDX) => #lookupDiscrAux(MORE, IDX -Int 1) requires 0 <Int IDX [owise]
1032+
1033+
syntax Int ::= #discriminantSize ( TypeInfo ) [function, total]
1034+
| #discriminantSize ( LayoutShape ) [function, total]
1035+
| #discriminantSize ( Scalar ) [function, total]
1036+
| #intLength (IntegerLength) [function, total]
1037+
// ------------------------------------------------------------
1038+
rule #discriminantSize(typeInfoEnumType(_, _, _, _, someLayoutShape(LAYOUT))) => #discriminantSize(LAYOUT)
1039+
rule #discriminantSize(_OTHER_TYPE:TypeInfo) => 0 [owise]
1040+
1041+
rule #discriminantSize(layoutShape(_, variantsShapeMultiple(mk(TAG, _, _, _)), _, _, _)) => #discriminantSize(TAG)
1042+
rule #discriminantSize(_OTHER:LayoutShape) => 0 [owise]
1043+
1044+
rule #discriminantSize(scalarInitialized(mk(primitiveInt(mk(INTLENGTH, _SIGNED)), _VALIDRANGE))) => #intLength(INTLENGTH)
1045+
rule #discriminantSize(scalarInitialized(mk(primitivePointer(_) , _VALIDRANGE))) => 64 // pointer size assumed 64 bit
1046+
rule #discriminantSize(_OTHER:Scalar) => 0 [owise]
1047+
1048+
rule #intLength(integerLengthI8) => 8
1049+
rule #intLength(integerLengthI16) => 16
1050+
rule #intLength(integerLengthI32) => 32
1051+
rule #intLength(integerLengthI64) => 64
1052+
rule #intLength(integerLengthI128) => 128
10311053
```
10321054

10331055
```k
@@ -1376,6 +1398,42 @@ What can be supported without additional layout consideration is trivial casts b
13761398
requires lookupTy(TY_SOURCE) ==K lookupTy(TY_TARGET)
13771399
```
13781400

1401+
Other `Transmute` casts that can be resolved are round-trip casts from type A to type B and then directly back from B to A.
1402+
The first cast is reified as a `thunk`, the second one resolves it and eliminates the `thunk`:
1403+
1404+
```k
1405+
rule <k> #cast(
1406+
thunk(#cast(DATA, castKindTransmute, TY_SRC_INNER, TY_DEST_INNER)),
1407+
castKindTransmute,
1408+
TY_SRC_OUTER,
1409+
TY_DEST_OUTER
1410+
) => DATA
1411+
...
1412+
</k>
1413+
requires lookupTy(TY_SRC_INNER) ==K lookupTy(TY_DEST_OUTER) // cast is a round-trip
1414+
andBool lookupTy(TY_DEST_INNER) ==K lookupTy(TY_SRC_OUTER) // and is well-formed (invariant)
1415+
```
1416+
1417+
Another specialisation is getting the discriminant of `enum`s without fields after converting some integer data to it
1418+
(see `#discriminant` and `rvalueDiscriminant`).
1419+
If none of the `enum` variants has any fields, the `Transmute` of a number to the `enum` data is necessarily just the discriminant itself., and can be returned as the integer value afgter adjusting to the byte length of the discriminant:
1420+
1421+
```k
1422+
rule <k> #discriminant(
1423+
thunk(#cast (Integer(DATA, _, false), castKindTransmute, _, TY)),
1424+
TY
1425+
) => Integer(DATA, #discriminantSize(lookupTy(TY)), false)
1426+
...
1427+
</k>
1428+
requires #isEnumWithoutFields(lookupTy(TY))
1429+
1430+
syntax Bool ::= #isEnumWithoutFields ( TypeInfo ) [function, total]
1431+
// ----------------------------------------------------------------
1432+
rule #isEnumWithoutFields(typeInfoEnumType(_, _, _, FIELDSS, _)) => #noFields(FIELDSS)
1433+
rule #isEnumWithoutFields(_OTHER) => false [owise]
1434+
```
1435+
1436+
13791437
### Other casts involving pointers
13801438

13811439
| CastKind | Description |
@@ -1527,16 +1585,14 @@ are correct.
15271585
// performs the given operation on infinite precision integers
15281586
syntax Int ::= onInt( BinOp, Int, Int ) [function]
15291587
// -----------------------------------------------
1530-
rule onInt(binOpAdd, X, Y) => X +Int Y
1531-
rule onInt(binOpAddUnchecked, X, Y) => X +Int Y
1532-
rule onInt(binOpSub, X, Y) => X -Int Y
1533-
rule onInt(binOpSubUnchecked, X, Y) => X -Int Y
1534-
rule onInt(binOpMul, X, Y) => X *Int Y
1535-
rule onInt(binOpMulUnchecked, X, Y) => X *Int Y
1536-
rule onInt(binOpDiv, X, Y) => X /Int Y
1537-
requires Y =/=Int 0
1538-
rule onInt(binOpRem, X, Y) => X %Int Y
1539-
requires Y =/=Int 0
1588+
rule onInt(binOpAdd, X, Y) => X +Int Y [preserves-definedness]
1589+
rule onInt(binOpAddUnchecked, X, Y) => X +Int Y [preserves-definedness]
1590+
rule onInt(binOpSub, X, Y) => X -Int Y [preserves-definedness]
1591+
rule onInt(binOpSubUnchecked, X, Y) => X -Int Y [preserves-definedness]
1592+
rule onInt(binOpMul, X, Y) => X *Int Y [preserves-definedness]
1593+
rule onInt(binOpMulUnchecked, X, Y) => X *Int Y [preserves-definedness]
1594+
rule onInt(binOpDiv, X, Y) => X /Int Y requires Y =/=Int 0 [preserves-definedness]
1595+
rule onInt(binOpRem, X, Y) => X %Int Y requires Y =/=Int 0 [preserves-definedness]
15401596
// operation undefined otherwise
15411597
15421598
// error cases for isArithmetic(BOP):

kmir/src/tests/integration/data/exec-smir/enum/enum.state

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
ListItem ( newLocal ( ty ( 16 ) , mutabilityNot ) )
4848
ListItem ( newLocal ( ty ( 28 ) , mutabilityNot ) )
4949
ListItem ( typedValue ( Moved , ty ( 6 ) , mutabilityMut ) )
50-
ListItem ( typedValue ( Integer ( 9090 , 128 , false ) , ty ( 29 ) , mutabilityMut ) )
50+
ListItem ( typedValue ( Integer ( 9090 , 16 , false ) , ty ( 29 ) , mutabilityMut ) )
5151
ListItem ( newLocal ( ty ( 26 ) , mutabilityNot ) )
5252
ListItem ( newLocal ( ty ( 28 ) , mutabilityMut ) )
5353
</locals>

0 commit comments

Comments
 (0)