Better support for conversions between number types.

This commit is contained in:
2020-01-10 09:04:47 -10:00
parent 8c5f18cb7c
commit 4b8d0b3f09
14 changed files with 96 additions and 35 deletions

View File

@@ -38,8 +38,8 @@ unsafeAddOps = File {
testCase = Just generateUnsafeTests testCase = Just generateUnsafeTests
} }
declareSafeAddOperators :: Word -> SourceFile Span declareSafeAddOperators :: Word -> [Word] -> SourceFile Span
declareSafeAddOperators bitsize = declareSafeAddOperators bitsize _ =
let sname = mkIdent ("U" ++ show bitsize) let sname = mkIdent ("U" ++ show bitsize)
dname = mkIdent ("U" ++ show (bitsize + 64)) dname = mkIdent ("U" ++ show (bitsize + 64))
fullRippleAdd = makeRippleAdder True (bitsize `div` 64) "res" fullRippleAdd = makeRippleAdder True (bitsize `div` 64) "res"
@@ -115,8 +115,8 @@ declareSafeAddOperators bitsize =
} }
|] |]
declareUnsafeAddOperators :: Word -> SourceFile Span declareUnsafeAddOperators :: Word -> [Word] -> SourceFile Span
declareUnsafeAddOperators bitsize = declareUnsafeAddOperators bitsize _ =
let sname = mkIdent ("U" ++ show bitsize) let sname = mkIdent ("U" ++ show bitsize)
fullRippleAdd = makeRippleAdder False (bitsize `div` 64) "self" fullRippleAdd = makeRippleAdder False (bitsize `div` 64) "self"
testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty

View File

@@ -20,8 +20,8 @@ base = File {
testCase = Nothing testCase = Nothing
} }
declareBaseStructure :: Word -> SourceFile Span declareBaseStructure :: Word -> [Word] -> SourceFile Span
declareBaseStructure bitsize = declareBaseStructure bitsize _ =
let tname = "U" ++ show bitsize let tname = "U" ++ show bitsize
entries = bitsize `div` 64 entries = bitsize `div` 64
sname = mkIdent tname sname = mkIdent tname

View File

@@ -28,8 +28,8 @@ binaryOps = File {
testCase = Just generateTests testCase = Just generateTests
} }
declareBinaryOperators :: Word -> SourceFile Span declareBinaryOperators :: Word -> [Word] -> SourceFile Span
declareBinaryOperators bitsize = declareBinaryOperators bitsize _ =
let struct_name = mkIdent ("U" ++ show bitsize) let struct_name = mkIdent ("U" ++ show bitsize)
entries = bitsize `div` 64 entries = bitsize `div` 64
andOps = generateBinOps "BitAnd" struct_name "bitand" BitAndOp entries andOps = generateBinOps "BitAnd" struct_name "bitand" BitAndOp entries

View File

@@ -24,8 +24,8 @@ comparisons = File {
testCase = Just generateTests testCase = Just generateTests
} }
declareComparators :: Word -> SourceFile Span declareComparators :: Word -> [Word] -> SourceFile Span
declareComparators bitsize = declareComparators bitsize _ =
let sname = mkIdent ("U" ++ show bitsize) let sname = mkIdent ("U" ++ show bitsize)
entries = bitsize `div` 64 entries = bitsize `div` 64
eqStatements = buildEqStatements 0 entries eqStatements = buildEqStatements 0 entries

View File

@@ -20,8 +20,8 @@ conversions = File {
testCase = Nothing testCase = Nothing
} }
declareConversions :: Word -> SourceFile Span declareConversions :: Word -> [Word] -> SourceFile Span
declareConversions bitsize = declareConversions bitsize otherSizes =
let sname = mkIdent ("U" ++ show bitsize) let sname = mkIdent ("U" ++ show bitsize)
entries = bitsize `div` 64 entries = bitsize `div` 64
u8_prims = buildPrimitives sname (mkIdent "u8") entries u8_prims = buildPrimitives sname (mkIdent "u8") entries
@@ -36,13 +36,14 @@ declareConversions bitsize =
i64_prims = generateSignedPrims sname (mkIdent "u64") (mkIdent "i64") i64_prims = generateSignedPrims sname (mkIdent "u64") (mkIdent "i64")
isz_prims = buildPrimitives sname (mkIdent "isize") entries isz_prims = buildPrimitives sname (mkIdent "isize") entries
i128_prims = generateI128Primitives sname i128_prims = generateI128Primitives sname
others = generateCryptonumConversions bitsize otherSizes
in [sourceFile| in [sourceFile|
use core::convert::{From,TryFrom}; use core::convert::{From,TryFrom};
use crate::CryptoNum; use crate::CryptoNum;
use crate::ConversionError; use crate::ConversionError;
#[cfg(test)] #[cfg(test)]
use quickcheck::quickcheck; use quickcheck::quickcheck;
use super::$$sname; use super::super::*;
$@{u8_prims} $@{u8_prims}
$@{u16_prims} $@{u16_prims}
@@ -58,6 +59,8 @@ declareConversions bitsize =
$@{isz_prims} $@{isz_prims}
$@{i128_prims} $@{i128_prims}
$@{others}
#[cfg(test)] #[cfg(test)]
quickcheck! { quickcheck! {
fn u8_recovers(x: u8) -> bool { fn u8_recovers(x: u8) -> bool {
@@ -244,3 +247,60 @@ generateI128Primitives sname = [
} }
}|] }|]
] ]
generateCryptonumConversions :: Word -> [Word] -> [Item Span]
generateCryptonumConversions source otherSizes = concatMap convert otherSizes
where
sName = mkIdent ("U" ++ show source)
--
convert target =
let tName = mkIdent ("U" ++ show target)
sEntries = toLit (source `div` 64)
tEntries = toLit (target `div` 64)
in case compare source target of
LT -> [
[item|
impl<'a> From<&'a $$sName> for $$tName {
fn from(x: &$$sName) -> $$tName {
let mut res = $$tName::zero();
res.value[0..$$(sEntries)].copy_from_slice(&x.value);
res
}
}
|],
[item|
impl From<$$sName> for $$tName {
fn from(x: $$sName) -> $$tName {
$$tName::from(&x)
}
}
|]
]
EQ -> []
GT -> [
[item|
impl<'a> TryFrom<&'a $$sName> for $$tName {
type Error = ConversionError;
fn try_from(x: &$$sName) -> Result<$$tName, ConversionError> {
if x.value.iter().skip($$(tEntries)).all(|x| *x == 0) {
let mut res = $$tName::zero();
res.value.copy_from_slice(&x.value[0..$$(tEntries)]);
Ok(res)
} else {
Err(ConversionError::Overflow)
}
}
}
|],
[item|
impl TryFrom<$$sName> for $$tName {
type Error = ConversionError;
fn try_from(x: $$sName) -> Result<$$tName, ConversionError> {
$$tName::try_from(&x)
}
}
|]
]

View File

@@ -28,8 +28,8 @@ cryptoNum = File {
testCase = Just generateTests testCase = Just generateTests
} }
declareCryptoNumInstance :: Word -> SourceFile Span declareCryptoNumInstance :: Word -> [Word] -> SourceFile Span
declareCryptoNumInstance bitsize = declareCryptoNumInstance bitsize _ =
let sname = mkIdent ("U" ++ show bitsize) let sname = mkIdent ("U" ++ show bitsize)
entries = bitsize `div` 64 entries = bitsize `div` 64
entlit = Lit [] (Int Dec (fromIntegral entries) Unsuffixed mempty) mempty entlit = Lit [] (Int Dec (fromIntegral entries) Unsuffixed mempty) mempty

View File

@@ -25,8 +25,8 @@ divisionOps = File {
testCase = Just generateDivisionTests testCase = Just generateDivisionTests
} }
declareDivision :: Word -> SourceFile Span declareDivision :: Word -> [Word] -> SourceFile Span
declareDivision size = declareDivision size _ =
let sname = mkIdent ("U" ++ show size) let sname = mkIdent ("U" ++ show size)
entries = size `div` 64 entries = size `div` 64
copyAssign = map doCopy [0..entries-1] copyAssign = map doCopy [0..entries-1]

View File

@@ -26,7 +26,7 @@ data File = File {
predicate :: Word -> [Word] -> Bool, predicate :: Word -> [Word] -> Bool,
outputName :: FilePath, outputName :: FilePath,
isUnsigned :: Bool, isUnsigned :: Bool,
generator :: Word -> SourceFile Span, generator :: Word -> [Word] -> SourceFile Span,
testCase :: forall g. RandomGen g => Maybe (Word -> g -> [Map String String]) testCase :: forall g. RandomGen g => Maybe (Word -> g -> [Map String String])
} }
@@ -62,7 +62,7 @@ generateTasks rng files sizes = basicTasks ++ moduleTasks
mainTask = Task { mainTask = Task {
outputFile = "src" </> signedBit </> ("u" ++ show size) </> outputFile = "src" </> signedBit </> ("u" ++ show size) </>
outputName file ++ ".rs", outputName file ++ ".rs",
writer = \ hndl -> writeSourceFile hndl (generator file size) writer = \ hndl -> writeSourceFile hndl (generator file size sizes)
} }
in case testCase file of in case testCase file of
Nothing -> Nothing ->

View File

@@ -7,6 +7,7 @@
module Karatsuba( module Karatsuba(
Instruction(..) Instruction(..)
, runChecks , runChecks
, runQuickCheck
, generateInstructions , generateInstructions
) )
where where

View File

@@ -26,8 +26,8 @@ modulusOps = File {
testCase = Just generateModulusTests testCase = Just generateModulusTests
} }
declareModOps :: Word -> SourceFile Span declareModOps :: Word -> [Word] -> SourceFile Span
declareModOps bitsize = declareModOps bitsize _ =
let sname = mkIdent ("U" ++ show bitsize) let sname = mkIdent ("U" ++ show bitsize)
bname = mkIdent ("U" ++ show (bitsize * 2)) bname = mkIdent ("U" ++ show (bitsize * 2))
in [sourceFile| in [sourceFile|

View File

@@ -40,8 +40,8 @@ unsafeMultiplyOps = File {
testCase = Just generateUnsafeTests testCase = Just generateUnsafeTests
} }
declareSafeMulOperators :: Word -> SourceFile Span declareSafeMulOperators :: Word -> [Word] -> SourceFile Span
declareSafeMulOperators bitsize = declareSafeMulOperators bitsize _ =
let sname = mkIdent ("U" ++ show bitsize) let sname = mkIdent ("U" ++ show bitsize)
dname = mkIdent ("U" ++ show (bitsize * 2)) dname = mkIdent ("U" ++ show (bitsize * 2))
fullRippleMul = generateMultiplier True (bitsize `div` 64) "rhs" "res" fullRippleMul = generateMultiplier True (bitsize `div` 64) "rhs" "res"
@@ -117,8 +117,8 @@ declareSafeMulOperators bitsize =
} }
|] |]
declareUnsafeMulOperators :: Word -> SourceFile Span declareUnsafeMulOperators :: Word -> [Word] -> SourceFile Span
declareUnsafeMulOperators bitsize = declareUnsafeMulOperators bitsize _ =
let sname = mkIdent ("U" ++ show bitsize) let sname = mkIdent ("U" ++ show bitsize)
halfRippleMul = generateMultiplier False (bitsize `div` 64) "rhs" "self" halfRippleMul = generateMultiplier False (bitsize `div` 64) "rhs" "self"
testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty

View File

@@ -38,8 +38,8 @@ unsafeScaleOps = File {
testCase = Just generateUnsafeTests testCase = Just generateUnsafeTests
} }
declareSafeScaleOperators :: Word -> SourceFile Span declareSafeScaleOperators :: Word -> [Word] -> SourceFile Span
declareSafeScaleOperators bitsize = declareSafeScaleOperators bitsize _ =
let sname = mkIdent ("U" ++ show bitsize) let sname = mkIdent ("U" ++ show bitsize)
dname = mkIdent ("U" ++ show (bitsize + 64)) dname = mkIdent ("U" ++ show (bitsize + 64))
fullRippleScale = generateScaletiplier True (bitsize `div` 64) "rhs" "res" fullRippleScale = generateScaletiplier True (bitsize `div` 64) "rhs" "res"
@@ -154,8 +154,8 @@ declareSafeScaleOperators bitsize =
} }
|] |]
declareUnsafeScaleOperators :: Word -> SourceFile Span declareUnsafeScaleOperators :: Word -> [Word] -> SourceFile Span
declareUnsafeScaleOperators bitsize = declareUnsafeScaleOperators bitsize _ =
let sname = mkIdent ("U" ++ show bitsize) let sname = mkIdent ("U" ++ show bitsize)
halfRippleScale = generateScaletiplier False (bitsize `div` 64) "rhs" "self" halfRippleScale = generateScaletiplier False (bitsize `div` 64) "rhs" "self"
testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty

View File

@@ -26,8 +26,8 @@ shiftOps = File {
testCase = Just generateTests testCase = Just generateTests
} }
declareShiftOperators :: Word -> SourceFile Span declareShiftOperators :: Word -> [Word] -> SourceFile Span
declareShiftOperators bitsize = declareShiftOperators bitsize _ =
let struct_name = mkIdent ("U" ++ show bitsize) let struct_name = mkIdent ("U" ++ show bitsize)
entries = bitsize `div` 64 entries = bitsize `div` 64
unsignedShifts = generateUnsigneds struct_name unsignedShifts = generateUnsigneds struct_name

View File

@@ -38,8 +38,8 @@ unsafeSubtractOps = File {
testCase = Just generateUnsafeTests testCase = Just generateUnsafeTests
} }
declareSafeSubtractOperators :: Word -> SourceFile Span declareSafeSubtractOperators :: Word -> [Word] -> SourceFile Span
declareSafeSubtractOperators bitsize = declareSafeSubtractOperators bitsize _ =
let sname = mkIdent ("U" ++ show bitsize) let sname = mkIdent ("U" ++ show bitsize)
dname = mkIdent ("U" ++ show (bitsize + 64)) dname = mkIdent ("U" ++ show (bitsize + 64))
fullRippleSubtract = makeRippleSubtracter True (bitsize `div` 64) "res" fullRippleSubtract = makeRippleSubtracter True (bitsize `div` 64) "res"
@@ -106,8 +106,8 @@ declareSafeSubtractOperators bitsize =
} }
|] |]
declareUnsafeSubtractOperators :: Word -> SourceFile Span declareUnsafeSubtractOperators :: Word -> [Word] -> SourceFile Span
declareUnsafeSubtractOperators bitsize = declareUnsafeSubtractOperators bitsize _ =
let sname = mkIdent ("U" ++ show bitsize) let sname = mkIdent ("U" ++ show bitsize)
fullRippleSubtract = makeRippleSubtracter False (bitsize `div` 64) "self" fullRippleSubtract = makeRippleSubtracter False (bitsize `div` 64) "self"
testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty