@@ -29,14 +29,13 @@ enum CastType {
2929 old_bit_size : u32 ,
3030 new_bit_size : u32 ,
3131 } ,
32- /// SignedField makes casting signed values more difficult since we need
33- /// to add an offset to make the signed value positive if it is negative,
34- /// and need to store a boolean to remember it is negative
35- SignedToField {
36- old_bit_size : u32 ,
37- } ,
3832 /// No-op also covers the zero-extend case since we convert between
3933 /// field elements rather than concrete bit sizes
34+ ///
35+ /// This is also the case for casting signed integers to fields.
36+ /// We represent negatives with two's complement, so e.g.
37+ /// `-1 as i8` is stored as the field value for `255`, and `255`
38+ /// is also the expected result of casting these to a field.
4039 Noop ,
4140}
4241
@@ -52,7 +51,7 @@ fn classify_cast(input: &Type, output: &Type) -> CastType {
5251 Ordering :: Less => {
5352 if input_signed {
5453 if output. is_field ( ) {
55- CastType :: SignedToField { old_bit_size : input_size }
54+ CastType :: Noop // We always zero-extend when casting to a field
5655 } else {
5756 CastType :: SignExtend { old_bit_size : input_size, new_bit_size : output_size }
5857 }
@@ -93,21 +92,6 @@ fn perform_cast(kind: CastType, lhs: FieldElement) -> FieldElement {
9392 lhs
9493 }
9594 }
96- CastType :: SignedToField { old_bit_size } => {
97- assert ! ( old_bit_size < 128 , "i128 and above are not supported" ) ;
98- let max_positive_value = 2u128 . pow ( old_bit_size - 1 ) - 1 ;
99- let is_negative = lhs > max_positive_value. into ( ) ;
100-
101- if !is_negative {
102- lhs
103- } else {
104- // We only return the FieldElement component of the SignedField, the caller
105- // needs to add the negative sign themselves
106- let max_negative_value = FieldElement :: from ( 2u128 . pow ( old_bit_size) ) ;
107- // E.g. `256 - 255 = 1` or `256 - 128 = 128`
108- max_negative_value - lhs
109- }
110- }
11195 CastType :: Noop => lhs,
11296 }
11397}
@@ -126,11 +110,12 @@ fn convert_to_field(value: Value, location: Location) -> IResult<(FieldElement,
126110 Value :: U32 ( value) => ( ( value as u128 ) . into ( ) , false ) ,
127111 Value :: U64 ( value) => ( ( value as u128 ) . into ( ) , false ) ,
128112 Value :: U128 ( value) => ( value. into ( ) , false ) ,
129- // Shared logic from ssa::interpreter::Value::convert_to_field
130- Value :: I8 ( value) => ( FieldElement :: from ( value as u8 as i128 ) , value < 0 ) ,
131- Value :: I16 ( value) => ( FieldElement :: from ( value as u16 as i128 ) , value < 0 ) ,
132- Value :: I32 ( value) => ( FieldElement :: from ( value as u32 as i128 ) , value < 0 ) ,
133- Value :: I64 ( value) => ( FieldElement :: from ( value as u64 as i128 ) , value < 0 ) ,
113+ // `is_negative` is only used for conversions to Field in which case
114+ // these should always be positive so that `-1 as i8 as Field == 255`
115+ Value :: I8 ( value) => ( FieldElement :: from ( value as u8 as i128 ) , false ) ,
116+ Value :: I16 ( value) => ( FieldElement :: from ( value as u16 as i128 ) , false ) ,
117+ Value :: I32 ( value) => ( FieldElement :: from ( value as u32 as i128 ) , false ) ,
118+ Value :: I64 ( value) => ( FieldElement :: from ( value as u64 as i128 ) , false ) ,
134119 Value :: Bool ( value) => ( FieldElement :: from ( value) , false ) ,
135120 value => {
136121 let typ = value. get_type ( ) . into_owned ( ) ;
@@ -264,10 +249,12 @@ mod tests {
264249 // Widen
265250 ( Value :: I8 ( 127 ) , unsigned ( SixtyFour ) , Value :: U64 ( 127 ) ) ,
266251 ( Value :: I8 ( 127 ) , signed ( SixtyFour ) , Value :: I64 ( 127 ) ) ,
267- // Widen negative: zero extend
252+ // Widen signed->unsigned: sign extend
268253 ( Value :: I8 ( -1 ) , unsigned ( Sixteen ) , Value :: U16 ( 65535 ) ) ,
269254 ( Value :: I8 ( -100 ) , unsigned ( Sixteen ) , Value :: U16 ( 65436 ) ) ,
270- ( Value :: I8 ( -100 ) , Type :: FieldElement , Value :: Field ( SignedField :: negative ( 100u32 ) ) ) ,
255+ // Casting a negative integer to a field always results in a positive value
256+ // This is the only case we zero-extend signed integers instead of sign-extending them
257+ ( Value :: I8 ( -1 ) , Type :: FieldElement , Value :: Field ( SignedField :: positive ( 255u32 ) ) ) ,
271258 // Widen negative: sign extend
272259 ( Value :: I8 ( -1 ) , signed ( Sixteen ) , Value :: I16 ( -1 ) ) ,
273260 ( Value :: I8 ( -100 ) , signed ( Sixteen ) , Value :: I16 ( -100 ) ) ,
0 commit comments