From 89c297525a68c6824a084c4178ab4c9ab01e5583 Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Thu, 23 Jan 2020 16:09:11 -0800 Subject: [PATCH] Improve the state of building, moving towards addition working for signed numbers. --- generation/src/Add.hs | 27 ++--- generation/src/Compare.hs | 21 ++-- generation/src/Conversions.hs | 189 +++++++++++++++++++++++++++++----- generation/src/Generators.hs | 12 +-- generation/src/Shift.hs | 6 +- generation/src/Subtract.hs | 8 +- 6 files changed, 199 insertions(+), 64 deletions(-) diff --git a/generation/src/Add.hs b/generation/src/Add.hs index 5cb76db..7cc9969 100644 --- a/generation/src/Add.hs +++ b/generation/src/Add.hs @@ -199,8 +199,7 @@ declareSafeSignedAddOperators :: Word -> [Word] -> SourceFile Span declareSafeSignedAddOperators bitsize _ = let sname = mkIdent ("I" ++ show bitsize) dname = mkIdent ("I" ++ show (bitsize + 64)) - fullRippleAdd = makeRippleAdder True (bitsize `div` 64) "res" - testFileLit = Lit [] (Str (testFile True bitsize) Cooked Unsuffixed mempty) mempty + testFileLit = Lit [] (Str (testFile False bitsize) Cooked Unsuffixed mempty) mempty in [sourceFile| use core::ops::Add; use crate::CryptoNum; @@ -238,7 +237,10 @@ declareSafeSignedAddOperators bitsize _ = type Output = $$dname; fn add(self, rhs: &$$sname) -> $$dname { - panic!("add") + let mut res = $$dname::from(self); + let bigrhs = $$dname::from(rhs); + res += bigrhs; + res } } @@ -261,9 +263,9 @@ declareSafeSignedAddOperators bitsize _ = let mut x = $$sname::from_bytes(&xbytes); let mut y = $$sname::from_bytes(&ybytes); let mut z = $$dname::from_bytes(&zbytes); - if neg0 { x = x.negate() } - if neg1 { y = y.negate() } - if neg2 { z = z.negate() } + if *neg0 { x = -x } + if *neg1 { y = -y } + if *neg2 { z = -z } assert_eq!(z, x + y); }); @@ -273,8 +275,7 @@ declareSafeSignedAddOperators bitsize _ = declareUnsafeSignedAddOperators :: Word -> [Word] -> SourceFile Span declareUnsafeSignedAddOperators bitsize _ = let sname = mkIdent ("I" ++ show bitsize) - fullRippleAdd = makeRippleAdder False (bitsize `div` 64) "self" - testFileLit = Lit [] (Str (testFile True bitsize) Cooked Unsuffixed mempty) mempty + testFileLit = Lit [] (Str (testFile False bitsize) Cooked Unsuffixed mempty) mempty in [sourceFile| use core::ops::AddAssign; #[cfg(test)] @@ -287,13 +288,13 @@ declareUnsafeSignedAddOperators bitsize _ = impl AddAssign for $$sname { fn add_assign(&mut self, rhs: Self) { - self.add_assign(&rhs); + self.contents += rhs.contents; } } impl<'a> AddAssign<&'a $$sname> for $$sname { fn add_assign(&mut self, rhs: &Self) { - panic!("add_assign") + self.contents += &rhs.contents; } } @@ -322,9 +323,9 @@ declareUnsafeSignedAddOperators bitsize _ = let mut x = $$sname::from_bytes(&xbytes); let mut y = $$sname::from_bytes(&ybytes); let mut z = $$sname::from_bytes(&zbytes); - if neg0 { x = x.negate() } - if neg1 { y = y.negate() } - if neg2 { z = z.negate() } + if *neg0 { x = -x } + if *neg1 { y = -y } + if *neg2 { z = -z } x += &y; assert_eq!(z, x); diff --git a/generation/src/Compare.hs b/generation/src/Compare.hs index 18df5d1..8ddc915 100644 --- a/generation/src/Compare.hs +++ b/generation/src/Compare.hs @@ -133,10 +133,7 @@ declareComparators bitsize _ = declareSignedComparators :: Word -> [Word] -> SourceFile Span declareSignedComparators bitsize _ = let sname = mkIdent ("I" ++ show bitsize) - entries = bitsize `div` 64 - eqStatements = buildEqStatements 0 entries - compareExp = buildCompareExp 0 entries - testFileLit = Lit [] (Str (testFile True bitsize) Cooked Unsuffixed mempty) mempty + testFileLit = Lit [] (Str (testFile False bitsize) Cooked Unsuffixed mempty) mempty in [sourceFile| use core::cmp::{Eq,Ordering,PartialEq}; #[cfg(test)] @@ -157,7 +154,12 @@ declareSignedComparators bitsize _ = impl Ord for $$sname { fn cmp(&self, other: &Self) -> Ordering { - panic!("cmp") + match (self.is_negative(), other.is_negative()) { + (false, false) => self.contents.cmp(&other.contents), + (false, true) => Ordering::Greater, + (true, false) => Ordering::Less, + (true, true) => self.contents.cmp(&other.contents), + } } } @@ -204,10 +206,11 @@ declareSignedComparators bitsize _ = let (neg6, lbytes) = case.get("l").unwrap(); let (neg7, kbytes) = case.get("k").unwrap(); - assert!(!neg0 && !neg1 && !neg2 && !neg3 && - !neg4 && !neg5 && !neg6 && !neg7); - let x = $$sname::from_bytes(&xbytes); - let y = $$sname::from_bytes(&ybytes); + assert!(!neg2 && !neg3 && !neg4 && !neg5 && !neg6 && !neg7); + let mut x = $$sname::from_bytes(&xbytes); + let mut y = $$sname::from_bytes(&ybytes); + if *neg0 { x = -x; } + if *neg1 { y = -y; } let e = 1 == ebytes[0]; let n = 1 == nbytes[0]; let g = 1 == gbytes[0]; diff --git a/generation/src/Conversions.hs b/generation/src/Conversions.hs index 9907ba9..ecf32ed 100644 --- a/generation/src/Conversions.hs +++ b/generation/src/Conversions.hs @@ -97,22 +97,23 @@ declareConversions bitsize otherSizes = declareSignedConversions :: Word -> [Word] -> SourceFile Span declareSignedConversions bitsize otherSizes = let sname = mkIdent ("I" ++ show bitsize) + uname = mkIdent ("U" ++ show bitsize) entries = bitsize `div` 64 - u8_prims = buildUSPrimitives sname (mkIdent "u8") entries - u16_prims = buildUSPrimitives sname (mkIdent "u16") entries - u32_prims = buildUSPrimitives sname (mkIdent "u32") entries - u64_prims = buildUSPrimitives sname (mkIdent "u64") entries - usz_prims = buildUSPrimitives sname (mkIdent "usize") entries - u128_prims = generateUS128Primitives sname entries - i8_prims = buildSSPrimitives sname (mkIdent "i8") entries - i16_prims = buildSSPrimitives sname (mkIdent "i16") entries - i32_prims = buildSSPrimitives sname (mkIdent "i32") entries - i64_prims = buildSSPrimitives sname (mkIdent "i64") entries - isz_prims = buildSSPrimitives sname (mkIdent "isize") entries - i128_prims = generateSS128Primitives sname entries + u8_prims = buildUSPrimitives sname (mkIdent "u8") + u16_prims = buildUSPrimitives sname (mkIdent "u16") + u32_prims = buildUSPrimitives sname (mkIdent "u32") + u64_prims = buildUSPrimitives sname (mkIdent "u64") + usz_prims = buildUSPrimitives sname (mkIdent "usize") + i8_prims = buildSSPrimitives sname uname (mkIdent "i8") + i16_prims = buildSSPrimitives sname uname (mkIdent "i16") + i32_prims = buildSSPrimitives sname uname (mkIdent "i32") + i64_prims = buildSSPrimitives sname uname (mkIdent "i64") + isz_prims = buildSSPrimitives sname uname (mkIdent "isize") + s128_prims = generateS128Primitives sname uname entries others = generateSignedCryptonumConversions bitsize otherSizes in [sourceFile| use core::convert::{From,TryFrom}; + use core::{i8,i16,i32,i64,isize}; use crate::CryptoNum; use crate::ConversionError; use crate::signed::*; @@ -125,14 +126,13 @@ declareSignedConversions bitsize otherSizes = $@{u32_prims} $@{u64_prims} $@{usz_prims} - $@{u128_prims} $@{i8_prims} $@{i16_prims} $@{i32_prims} $@{i64_prims} $@{isz_prims} - $@{i128_prims} + $@{s128_prims} $@{others} @@ -156,6 +156,24 @@ declareSignedConversions bitsize otherSizes = fn u128_recovers(x: u128) -> bool { x == u128::try_from($$sname::from(x)).unwrap() } + fn i8_recovers(x: i8) -> bool { + x == i8::try_from($$sname::from(x)).unwrap() + } + fn i16_recovers(x: i16) -> bool { + x == i16::try_from($$sname::from(x)).unwrap() + } + fn i32_recovers(x: i32) -> bool { + x == i32::try_from($$sname::from(x)).unwrap() + } + fn i64_recovers(x: i64) -> bool { + x == i64::try_from($$sname::from(x)).unwrap() + } + fn isize_recovers(x: isize) -> bool { + x == isize::try_from($$sname::from(x)).unwrap() + } + fn i128_recovers(x: i128) -> bool { + x == i128::try_from($$sname::from(x)).unwrap() + } } |] @@ -324,7 +342,7 @@ generateI128Primitives sname = [ ] generateCryptonumConversions :: Word -> [Word] -> [Item Span] -generateCryptonumConversions source otherSizes = concatMap convert otherSizes +generateCryptonumConversions source = concatMap convert where sName = mkIdent ("U" ++ show source) -- @@ -379,8 +397,8 @@ generateCryptonumConversions source otherSizes = concatMap convert otherSizes |] ] -buildUSPrimitives :: Ident -> Ident -> Word -> [Item Span] -buildUSPrimitives sname prim entries = [ +buildUSPrimitives :: Ident -> Ident -> [Item Span] +buildUSPrimitives sname prim = [ [item| impl From<$$prim> for $$sname { fn from(x: $$prim) -> $$sname { @@ -417,12 +435,18 @@ buildUSPrimitives sname prim entries = [ |] ] -buildSSPrimitives :: Ident -> Ident -> Word -> [Item Span] -buildSSPrimitives sname prim entries = [ +buildSSPrimitives :: Ident -> Ident -> Ident -> [Item Span] +buildSSPrimitives sname uname prim = [ [item| impl From<$$prim> for $$sname { fn from(x: $$prim) -> $$sname { - panic!("from_signed") + let mut ures = $$uname::zero(); + let topbits = if x < 0 { 0xFFFF_FFFF_FFFF_FFFF } else { 0 }; + for x in ures.value.iter_mut() { + *x = topbits; + } + ures.value[0] = (x as i64) as u64; + $$sname{ contents: ures } } } |] @@ -431,7 +455,19 @@ buildSSPrimitives sname prim entries = [ type Error = ConversionError; fn try_from(x: &$$sname) -> Result<$$prim, ConversionError> { - panic!("try_from_signed") + let topbits = if x.is_negative() { 0xFFFF_FFFF_FFFF_FFFF } else { 0 }; + if x.contents.value[1..].iter().any(|v| *v != topbits) { + return Err(ConversionError::Overflow); + } + let local_min = $$prim::MIN as i64; + let local_max = $$prim::MAX as i64; + let bottom = x.contents.value[0] as i64; + + if (bottom > local_max) || (bottom < local_min) { + Err(ConversionError::Overflow) + } else { + Ok(bottom as $$prim) + } } } |] @@ -446,11 +482,80 @@ buildSSPrimitives sname prim entries = [ |] ] -generateUS128Primitives :: Ident -> Word -> [Item Span] -generateUS128Primitives struct entries = [] +generateS128Primitives :: Ident -> Ident -> Word -> [Item Span] +generateS128Primitives sname uname entries = [ + [item| + impl From for $$sname { + fn from(x: u128) -> $$sname { + $$sname{ contents: $$uname::from(x) } + } + } + |], + [item| + impl From for $$sname { + fn from(x: i128) -> $$sname { + let mut basic = $$uname::from(x as u128); + if x < 0 { + for x in basic.value[2..].iter_mut() { + *x = 0xFFFF_FFFF_FFFF_FFFF; + } + } + $$sname{ contents: basic } + } + } + |], + [item| + impl TryFrom<$$sname> for u128 { + type Error = ConversionError; -generateSS128Primitives :: Ident -> Word -> [Item Span] -generateSS128Primitives struct entries = [] + fn try_from(x: $$sname) -> Result { + u128::try_from(&x) + } + } + |], + [item| + impl TryFrom<$$sname> for i128 { + type Error = ConversionError; + + fn try_from(x: $$sname) -> Result { + i128::try_from(&x) + } + } + |], + [item| + impl<'a> TryFrom<&'a $$sname> for u128 { + type Error = ConversionError; + + fn try_from(x: &$$sname) -> Result { + if x.is_negative() { + return Err(ConversionError::Overflow); + } + u128::try_from(&x.contents) + } + } + |], + [item| + impl<'a> TryFrom<&'a $$sname> for i128 { + type Error = ConversionError; + + fn try_from(x: &$$sname) -> Result { + let isneg = x.is_negative(); + let target_top = if isneg { 0xFFFF_FFFF_FFFF_FFFF } else { 0x0 }; + let mut worked = true; + + worked &= x.contents.value[2..].iter().all(|v| *v == target_top); + worked &= (x.contents.value[1] >> 63 == 1) == isneg; + + let res = ((x.contents.value[1] as u128) << 64) | (x.contents.value[0] as u128); + if worked { + Ok(res as i128) + } else { + Err(ConversionError::Overflow) + } + } + } + |] + ] generateSignedCryptonumConversions :: Word -> [Word] -> [Item Span] generateSignedCryptonumConversions source otherSizes = concatMap convert otherSizes @@ -463,7 +568,8 @@ generateSignedCryptonumConversions source otherSizes = concatMap convert otherSi sEntries = toLit (source `div` 64) tEntries = toLit (target `div` 64) in case compare source target of - LT -> [] + LT -> [ + ] EQ -> [ [item| impl TryFrom<$$tuName> for $$sName { @@ -511,5 +617,34 @@ generateSignedCryptonumConversions source otherSizes = concatMap convert otherSi } |] ] - GT -> [] + GT -> [ + [item| + impl From<$$tuName> for $$sName { + fn from(x: $$tuName) -> $$sName { + $$sName::from(&x) + } + } + |], + [item| + impl<'a> From<&'a $$tuName> for $$sName { + fn from(x: &$$tuName) -> $$sName { + panic!("from1") + } + } + |], + [item| + impl From<$$tsName> for $$sName { + fn from(x: $$tsName) -> $$sName { + $$sName::from(&x) + } + } + |], + [item| + impl<'a> From<&'a $$tsName> for $$sName { + fn from(x: &$$tsName) -> $$sName { + panic!("from2") + } + } + |] + ] diff --git a/generation/src/Generators.hs b/generation/src/Generators.hs index c30f79b..d407a63 100644 --- a/generation/src/Generators.hs +++ b/generation/src/Generators.hs @@ -2,7 +2,7 @@ module Generators where import Numeric(showHex) -import System.Random(RandomGen,random) +import System.Random(RandomGen,random,randomR) generateNum :: RandomGen g => g -> Word -> (Integer, g) generateNum g size = @@ -12,12 +12,10 @@ generateNum g size = generateSignedNum :: RandomGen g => g -> Word -> (Integer, g) generateSignedNum g size = - let (x, g') = random g - s :: Integer - (s, g'') = random g' - x' = x `mod` (2 ^ size) - sign = if even s then 1 else -1 - in (x' * sign, g'') + let biggest = (2 ^ (size - 1)) - 1 + smallest = - (2 ^ (size - 1)) + (x, g') = randomR (smallest, biggest) g + in (x, g') modulate :: (Integral a, Integral b) => a -> b -> Integer modulate x size = x' `mod` (2 ^ size') diff --git a/generation/src/Shift.hs b/generation/src/Shift.hs index 864a10e..82bd5ae 100644 --- a/generation/src/Shift.hs +++ b/generation/src/Shift.hs @@ -157,9 +157,9 @@ declareSignedShiftOperators bitsize _ = let mut l = $$struct_name::from_bytes(lbytes); let mut r = $$struct_name::from_bytes(rbytes); - if neg0 { x = x.negate() } - if neg2 { l = l.negate() } - if neg3 { r = r.negate() } + if *neg0 { x = -x } + if *neg2 { l = -l } + if *neg3 { r = -r } let s = usize::try_from($$struct_name::from_bytes(sbytes)).unwrap(); assert_eq!(l, &x << s); diff --git a/generation/src/Subtract.hs b/generation/src/Subtract.hs index 1aaa413..58d96d7 100644 --- a/generation/src/Subtract.hs +++ b/generation/src/Subtract.hs @@ -130,7 +130,6 @@ declareSafeSignedSubtractOperators :: Word -> [Word] -> SourceFile Span declareSafeSignedSubtractOperators bitsize _ = let sname = mkIdent ("I" ++ show bitsize) dname = mkIdent ("I" ++ show (bitsize + 64)) - fullRippleSubtract = makeRippleSubtracter True (bitsize `div` 64) "res" testFileLit = Lit [] (Str (testFile True bitsize) Cooked Unsuffixed mempty) mempty in [sourceFile| use core::ops::Sub; @@ -238,7 +237,6 @@ declareUnsafeSubtractOperators bitsize _ = declareUnsafeSignedSubtractOperators :: Word -> [Word] -> SourceFile Span declareUnsafeSignedSubtractOperators bitsize _ = let sname = mkIdent ("I" ++ show bitsize) - fullRippleSubtract = makeRippleSubtracter False (bitsize `div` 64) "self" testFileLit = Lit [] (Str (testFile True bitsize) Cooked Unsuffixed mempty) mempty in [sourceFile| use core::ops::SubAssign; @@ -272,9 +270,9 @@ declareUnsafeSignedSubtractOperators bitsize _ = let mut x = $$sname::from_bytes(&xbytes); let mut y = $$sname::from_bytes(&ybytes); let mut z = $$sname::from_bytes(&zbytes); - if neg0 { x = x.negate(); } - if neg1 { y = y.negate(); } - if neg2 { z = z.negate(); } + if *neg0 { x = -x; } + if *neg1 { y = -y; } + if *neg2 { z = -z; } x -= &y; assert_eq!(z, x);