Skip to content

Commit 9222a76

Browse files
authored
Hotfix byte number conversion optimisations (#824)
* avoids using `/Int` and `%Int` in the byte-to-number conversions * modifies the tests to exhibit a bit more complicated expressions * Adds targeted simplifications to make the modified tests pass
1 parent 5b8ce03 commit 9222a76

File tree

3 files changed

+36
-9
lines changed

3 files changed

+36
-9
lines changed

kmir/src/kmir/kdist/mir-semantics/lemmas/kmir-lemmas.md

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,18 +118,39 @@ power of two but the semantics will always operate with these particular ones.
118118
rule VAL &Int bitmask128 => VAL requires 0 <=Int VAL andBool VAL <=Int bitmask128 [simplification, preserves-definedness, smt-lemma]
119119
```
120120

121+
Support for `transmute` between byte arrays and numbers (and vice-versa) uses computations involving bit masks with 255 and 8-bit shifts.
122+
To support simplifying round-trip conversion, the following simplifications are essential.
123+
121124
```k
122-
rule (VAL +Int 256 *Int REST) %Int 256 => VAL
125+
rule (VAL +Int 256 *Int REST) &Int 255 => VAL
123126
requires 0 <=Int VAL
124127
andBool VAL <=Int 255
125128
andBool 0 <=Int REST
126129
[simplification, preserves-definedness]
127130
128-
rule (VAL +Int 256 *Int REST) /Int 256 => REST
131+
rule (VAL +Int 256 *Int REST) >>Int 8 => REST
129132
requires 0 <=Int VAL
130133
andBool VAL <=Int 255
131134
andBool 0 <=Int REST
132135
[simplification, preserves-definedness]
136+
137+
rule (_ &Int 255) <=Int 255 => true
138+
[simplification, preserves-definedness]
139+
rule 0 <=Int (_ &Int 255) => true
140+
[simplification, preserves-definedness]
141+
142+
rule [simplify-u64-bytes-u64]:
143+
(VAL &Int 255) +Int (256 *Int (
144+
((VAL >>Int 8) &Int 255) +Int (256 *Int (
145+
((VAL >>Int 8 >>Int 8) &Int 255) +Int (256 *Int (
146+
((VAL >>Int 8 >>Int 8 >>Int 8) &Int 255) +Int (256 *Int (
147+
((VAL >>Int 8 >>Int 8 >>Int 8 >>Int 8) &Int 255) +Int (256 *Int (
148+
((VAL >>Int 8 >>Int 8 >>Int 8 >>Int 8 >>Int 8) &Int 255) +Int (256 *Int (
149+
((VAL >>Int 8 >>Int 8 >>Int 8 >>Int 8 >>Int 8 >>Int 8) &Int 255) +Int (256 *Int (
150+
((VAL >>Int 8 >>Int 8 >>Int 8 >>Int 8 >>Int 8 >>Int 8 >>Int 8) &Int 255)))))))))))))))
151+
=> VAL
152+
requires 0 <=Int VAL andBool VAL <=Int bitmask64
153+
[simplification, preserves-definedness, symbolic(VAL)]
133154
```
134155

135156

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1459,16 +1459,16 @@ Casting an integer to a `[u8; N]` array materialises its little-endian bytes.
14591459
...
14601460
</k>
14611461
requires #isStaticU8Array(lookupTy(TY_TARGET))
1462-
andBool WIDTH >=Int 0
1463-
andBool WIDTH %Int 8 ==Int 0
14641462
andBool WIDTH ==Int #staticArrayLenBits(lookupTy(TY_TARGET))
1463+
// andBool WIDTH >=Int 0 ensured by the above
1464+
// andBool WIDTH % 8 == 0 ensured by the above
14651465
[preserves-definedness] // ensures element type/length are well-formed
14661466
14671467
syntax List ::= #littleEndianBytesFromInt ( Int, Int ) [function]
14681468
// -------------------------------------------------------------
14691469
rule #littleEndianBytesFromInt(VAL, WIDTH)
1470-
=> #littleEndianBytes(truncate(VAL, WIDTH, Unsigned), WIDTH /Int 8)
1471-
requires WIDTH %Int 8 ==Int 0
1470+
=> #littleEndianBytes(truncate(VAL, WIDTH, Unsigned), WIDTH >>Int 3)
1471+
requires WIDTH &Int 7 ==Int 0 // WIDTH % 8 == 0
14721472
andBool WIDTH >=Int 0
14731473
[preserves-definedness]
14741474
@@ -1479,7 +1479,7 @@ Casting an integer to a `[u8; N]` array materialises its little-endian bytes.
14791479
requires COUNT <=Int 0
14801480
14811481
rule #littleEndianBytes(VAL, COUNT)
1482-
=> ListItem(Integer(VAL %Int 256, 8, false)) #littleEndianBytes(VAL /Int 256, COUNT -Int 1)
1482+
=> ListItem(Integer(VAL &Int 255, 8, false)) #littleEndianBytes(VAL >>Int 8, COUNT -Int 1)
14831483
requires COUNT >Int 0
14841484
[preserves-definedness]
14851485

kmir/src/tests/integration/data/prove-rs/transmute-bytes.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,19 @@ use std::mem::transmute;
55

66
fn bytes_to_u64(bytes: [u8; 8]) -> u64 {
77
let value = unsafe { transmute::<[u8; 8], u64>(bytes) };
8-
let roundtrip = unsafe { transmute::<u64, [u8; 8]>(value) };
8+
// prevent round-trip-transmute rule from simplifying this
9+
let enlarged = value as u128;
10+
let original = enlarged as u64;
11+
let roundtrip = unsafe { transmute::<u64, [u8; 8]>(original) };
912
assert_eq!(roundtrip, bytes);
1013
value
1114
}
1215

1316
fn u64_to_bytes(value: u64) -> [u8; 8] {
14-
let bytes = unsafe { transmute::<u64, [u8; 8]>(value) };
17+
let mut bytes = unsafe { transmute::<u64, [u8; 8]>(value) };
18+
let first = bytes[0];
19+
bytes[0] = 255u8;
20+
bytes[0] = first;
1521
let roundtrip = unsafe { transmute::<[u8; 8], u64>(bytes) };
1622
assert_eq!(roundtrip, value);
1723
bytes

0 commit comments

Comments
 (0)