Generate one file per type, rather than ... quite a few.
This commit is contained in:
@@ -13,11 +13,11 @@ import CryptoNum(cryptoNum)
|
|||||||
import Control.Monad(forM_,unless)
|
import Control.Monad(forM_,unless)
|
||||||
import Data.Text.Lazy(Text, pack)
|
import Data.Text.Lazy(Text, pack)
|
||||||
import Division(divisionOps)
|
import Division(divisionOps)
|
||||||
import File(File,Task(..),generateTasks)
|
|
||||||
import GHC.Conc(getNumCapabilities)
|
import GHC.Conc(getNumCapabilities)
|
||||||
import ModInv(generateModInvOps)
|
import ModInv(generateModInvOps)
|
||||||
import ModOps(modulusOps)
|
import ModOps(modulusOps)
|
||||||
import Multiply(safeMultiplyOps, unsafeMultiplyOps)
|
import Multiply(safeMultiplyOps, unsafeMultiplyOps)
|
||||||
|
import RustModule(RustModule,Task(..),generateTasks)
|
||||||
import Scale(safeScaleOps, unsafeScaleOps)
|
import Scale(safeScaleOps, unsafeScaleOps)
|
||||||
import Shift(shiftOps, signedShiftOps)
|
import Shift(shiftOps, signedShiftOps)
|
||||||
import Signed(signedBaseOps)
|
import Signed(signedBaseOps)
|
||||||
@@ -39,7 +39,7 @@ highestBitsize = 512
|
|||||||
bitsizes :: [Word]
|
bitsizes :: [Word]
|
||||||
bitsizes = [lowestBitsize,lowestBitsize+64..highestBitsize]
|
bitsizes = [lowestBitsize,lowestBitsize+64..highestBitsize]
|
||||||
|
|
||||||
unsignedFiles :: [File]
|
unsignedFiles :: [RustModule]
|
||||||
unsignedFiles = [
|
unsignedFiles = [
|
||||||
base
|
base
|
||||||
, binaryOps
|
, binaryOps
|
||||||
@@ -60,7 +60,7 @@ unsignedFiles = [
|
|||||||
, unsafeSubtractOps
|
, unsafeSubtractOps
|
||||||
]
|
]
|
||||||
|
|
||||||
signedFiles :: [File]
|
signedFiles :: [RustModule]
|
||||||
signedFiles = [
|
signedFiles = [
|
||||||
safeSignedAddOps
|
safeSignedAddOps
|
||||||
, safeSignedSubtractOps
|
, safeSignedSubtractOps
|
||||||
@@ -72,7 +72,7 @@ signedFiles = [
|
|||||||
, unsafeSignedSubtractOps
|
, unsafeSignedSubtractOps
|
||||||
]
|
]
|
||||||
|
|
||||||
allFiles :: [File]
|
allFiles :: [RustModule]
|
||||||
allFiles = unsignedFiles ++ signedFiles
|
allFiles = unsignedFiles ++ signedFiles
|
||||||
|
|
||||||
printLast :: Progress String -> Timing -> Text
|
printLast :: Progress String -> Timing -> Text
|
||||||
|
|||||||
@@ -37,13 +37,13 @@ library
|
|||||||
Conversions,
|
Conversions,
|
||||||
CryptoNum,
|
CryptoNum,
|
||||||
Division,
|
Division,
|
||||||
File,
|
|
||||||
Gen,
|
Gen,
|
||||||
Generators,
|
Generators,
|
||||||
Karatsuba,
|
Karatsuba,
|
||||||
ModInv,
|
ModInv,
|
||||||
ModOps,
|
ModOps,
|
||||||
Multiply,
|
Multiply,
|
||||||
|
RustModule,
|
||||||
Scale,
|
Scale,
|
||||||
Shift,
|
Shift,
|
||||||
Signed,
|
Signed,
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ module Add(
|
|||||||
import Data.Bits((.&.))
|
import Data.Bits((.&.))
|
||||||
import Data.Map.Strict(Map)
|
import Data.Map.Strict(Map)
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import File
|
|
||||||
import Gen(toLit)
|
import Gen(toLit)
|
||||||
import Generators
|
import Generators
|
||||||
import Language.Rust.Data.Ident
|
import Language.Rust.Data.Ident
|
||||||
@@ -19,11 +18,12 @@ import Language.Rust.Quote
|
|||||||
import Language.Rust.Syntax
|
import Language.Rust.Syntax
|
||||||
import System.Random(RandomGen)
|
import System.Random(RandomGen)
|
||||||
|
|
||||||
|
import RustModule
|
||||||
numTestCases :: Int
|
numTestCases :: Int
|
||||||
numTestCases = 3000
|
numTestCases = 3000
|
||||||
|
|
||||||
safeAddOps :: File
|
safeAddOps :: RustModule
|
||||||
safeAddOps = File {
|
safeAddOps = RustModule {
|
||||||
predicate = \ me others -> (me + 64) `elem` others,
|
predicate = \ me others -> (me + 64) `elem` others,
|
||||||
outputName = "safe_add",
|
outputName = "safe_add",
|
||||||
isUnsigned = True,
|
isUnsigned = True,
|
||||||
@@ -31,8 +31,8 @@ safeAddOps = File {
|
|||||||
testCase = Just generateSafeTests
|
testCase = Just generateSafeTests
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafeAddOps :: File
|
unsafeAddOps :: RustModule
|
||||||
unsafeAddOps = File {
|
unsafeAddOps = RustModule {
|
||||||
predicate = \ _ _ -> True,
|
predicate = \ _ _ -> True,
|
||||||
outputName = "unsafe_add",
|
outputName = "unsafe_add",
|
||||||
isUnsigned = True,
|
isUnsigned = True,
|
||||||
@@ -40,8 +40,8 @@ unsafeAddOps = File {
|
|||||||
testCase = Just generateUnsafeTests
|
testCase = Just generateUnsafeTests
|
||||||
}
|
}
|
||||||
|
|
||||||
safeSignedAddOps :: File
|
safeSignedAddOps :: RustModule
|
||||||
safeSignedAddOps = File {
|
safeSignedAddOps = RustModule {
|
||||||
predicate = \ me others -> (me + 64) `elem` others,
|
predicate = \ me others -> (me + 64) `elem` others,
|
||||||
outputName = "safe_sadd",
|
outputName = "safe_sadd",
|
||||||
isUnsigned = False,
|
isUnsigned = False,
|
||||||
@@ -49,8 +49,8 @@ safeSignedAddOps = File {
|
|||||||
testCase = Just generateSafeSignedTests
|
testCase = Just generateSafeSignedTests
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafeSignedAddOps :: File
|
unsafeSignedAddOps :: RustModule
|
||||||
unsafeSignedAddOps = File {
|
unsafeSignedAddOps = RustModule {
|
||||||
predicate = \ _ _ -> True,
|
predicate = \ _ _ -> True,
|
||||||
outputName = "unsafe_sadd",
|
outputName = "unsafe_sadd",
|
||||||
isUnsigned = False,
|
isUnsigned = False,
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ module Base(
|
|||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import File
|
|
||||||
import Language.Rust.Data.Ident
|
import Language.Rust.Data.Ident
|
||||||
import Language.Rust.Data.Position
|
import Language.Rust.Data.Position
|
||||||
import Language.Rust.Quote
|
import Language.Rust.Quote
|
||||||
import Language.Rust.Syntax
|
import Language.Rust.Syntax
|
||||||
|
import RustModule
|
||||||
|
|
||||||
base :: File
|
base :: RustModule
|
||||||
base = File {
|
base = RustModule {
|
||||||
predicate = \ _ _ -> True,
|
predicate = \ _ _ -> True,
|
||||||
outputName = "base",
|
outputName = "base",
|
||||||
isUnsigned = True,
|
isUnsigned = True,
|
||||||
|
|||||||
@@ -7,20 +7,20 @@ module BinaryOps(
|
|||||||
import Data.Bits(xor,(.&.),(.|.))
|
import Data.Bits(xor,(.&.),(.|.))
|
||||||
import Data.Map.Strict(Map)
|
import Data.Map.Strict(Map)
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import File
|
|
||||||
import Gen(toLit)
|
import Gen(toLit)
|
||||||
import Generators
|
import Generators
|
||||||
import Language.Rust.Data.Ident
|
import Language.Rust.Data.Ident
|
||||||
import Language.Rust.Data.Position
|
import Language.Rust.Data.Position
|
||||||
import Language.Rust.Quote
|
import Language.Rust.Quote
|
||||||
import Language.Rust.Syntax
|
import Language.Rust.Syntax
|
||||||
|
import RustModule
|
||||||
import System.Random(RandomGen)
|
import System.Random(RandomGen)
|
||||||
|
|
||||||
numTestCases :: Int
|
numTestCases :: Int
|
||||||
numTestCases = 3000
|
numTestCases = 3000
|
||||||
|
|
||||||
binaryOps :: File
|
binaryOps :: RustModule
|
||||||
binaryOps = File {
|
binaryOps = RustModule {
|
||||||
predicate = \ _ _ -> True,
|
predicate = \ _ _ -> True,
|
||||||
outputName = "binary",
|
outputName = "binary",
|
||||||
isUnsigned = True,
|
isUnsigned = True,
|
||||||
|
|||||||
@@ -4,19 +4,19 @@ module Compare(comparisons, signedComparisons)
|
|||||||
|
|
||||||
import Data.Map.Strict(Map)
|
import Data.Map.Strict(Map)
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import File
|
|
||||||
import Generators
|
import Generators
|
||||||
import Language.Rust.Data.Ident
|
import Language.Rust.Data.Ident
|
||||||
import Language.Rust.Data.Position
|
import Language.Rust.Data.Position
|
||||||
import Language.Rust.Quote
|
import Language.Rust.Quote
|
||||||
import Language.Rust.Syntax
|
import Language.Rust.Syntax
|
||||||
|
import RustModule
|
||||||
import System.Random(RandomGen)
|
import System.Random(RandomGen)
|
||||||
|
|
||||||
numTestCases :: Int
|
numTestCases :: Int
|
||||||
numTestCases = 3000
|
numTestCases = 3000
|
||||||
|
|
||||||
comparisons :: File
|
comparisons :: RustModule
|
||||||
comparisons = File {
|
comparisons = RustModule {
|
||||||
predicate = \ _ _ -> True,
|
predicate = \ _ _ -> True,
|
||||||
outputName = "compare",
|
outputName = "compare",
|
||||||
isUnsigned = True,
|
isUnsigned = True,
|
||||||
@@ -24,8 +24,8 @@ comparisons = File {
|
|||||||
testCase = Just generateTests
|
testCase = Just generateTests
|
||||||
}
|
}
|
||||||
|
|
||||||
signedComparisons :: File
|
signedComparisons :: RustModule
|
||||||
signedComparisons = File {
|
signedComparisons = RustModule {
|
||||||
predicate = \ _ _ -> True,
|
predicate = \ _ _ -> True,
|
||||||
outputName = "scompare",
|
outputName = "scompare",
|
||||||
isUnsigned = False,
|
isUnsigned = False,
|
||||||
|
|||||||
@@ -5,15 +5,15 @@ module Conversions(
|
|||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import File
|
|
||||||
import Gen(toLit)
|
import Gen(toLit)
|
||||||
import Language.Rust.Data.Ident
|
import Language.Rust.Data.Ident
|
||||||
import Language.Rust.Data.Position
|
import Language.Rust.Data.Position
|
||||||
import Language.Rust.Quote
|
import Language.Rust.Quote
|
||||||
import Language.Rust.Syntax
|
import Language.Rust.Syntax
|
||||||
|
import RustModule
|
||||||
|
|
||||||
conversions :: File
|
conversions :: RustModule
|
||||||
conversions = File {
|
conversions = RustModule {
|
||||||
predicate = \ _ _ -> True,
|
predicate = \ _ _ -> True,
|
||||||
outputName = "conversions",
|
outputName = "conversions",
|
||||||
isUnsigned = True,
|
isUnsigned = True,
|
||||||
@@ -21,8 +21,8 @@ conversions = File {
|
|||||||
testCase = Nothing
|
testCase = Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
signedConversions :: File
|
signedConversions :: RustModule
|
||||||
signedConversions = File {
|
signedConversions = RustModule {
|
||||||
predicate = \ _ _ -> True,
|
predicate = \ _ _ -> True,
|
||||||
outputName = "sconversions",
|
outputName = "sconversions",
|
||||||
isUnsigned = False,
|
isUnsigned = False,
|
||||||
|
|||||||
@@ -7,20 +7,20 @@ module CryptoNum(
|
|||||||
import Data.Bits(testBit)
|
import Data.Bits(testBit)
|
||||||
import Data.Map.Strict(Map)
|
import Data.Map.Strict(Map)
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import File
|
|
||||||
import Gen
|
import Gen
|
||||||
import Generators
|
import Generators
|
||||||
import Language.Rust.Data.Ident
|
import Language.Rust.Data.Ident
|
||||||
import Language.Rust.Data.Position
|
import Language.Rust.Data.Position
|
||||||
import Language.Rust.Quote
|
import Language.Rust.Quote
|
||||||
import Language.Rust.Syntax
|
import Language.Rust.Syntax
|
||||||
|
import RustModule
|
||||||
import System.Random(RandomGen)
|
import System.Random(RandomGen)
|
||||||
|
|
||||||
numTestCases :: Int
|
numTestCases :: Int
|
||||||
numTestCases = 3000
|
numTestCases = 3000
|
||||||
|
|
||||||
cryptoNum :: File
|
cryptoNum :: RustModule
|
||||||
cryptoNum = File {
|
cryptoNum = RustModule {
|
||||||
predicate = \ _ _ -> True,
|
predicate = \ _ _ -> True,
|
||||||
outputName = "cryptonum",
|
outputName = "cryptonum",
|
||||||
isUnsigned = True,
|
isUnsigned = True,
|
||||||
|
|||||||
@@ -4,20 +4,20 @@ module Division(divisionOps)
|
|||||||
|
|
||||||
import Data.Map.Strict(Map)
|
import Data.Map.Strict(Map)
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import File
|
|
||||||
import Gen(toLit)
|
import Gen(toLit)
|
||||||
import Generators
|
import Generators
|
||||||
import Language.Rust.Data.Ident
|
import Language.Rust.Data.Ident
|
||||||
import Language.Rust.Data.Position
|
import Language.Rust.Data.Position
|
||||||
import Language.Rust.Quote
|
import Language.Rust.Quote
|
||||||
import Language.Rust.Syntax
|
import Language.Rust.Syntax
|
||||||
|
import RustModule
|
||||||
import System.Random(RandomGen)
|
import System.Random(RandomGen)
|
||||||
|
|
||||||
numTestCases :: Int
|
numTestCases :: Int
|
||||||
numTestCases = 3000
|
numTestCases = 3000
|
||||||
|
|
||||||
divisionOps :: File
|
divisionOps :: RustModule
|
||||||
divisionOps = File {
|
divisionOps = RustModule {
|
||||||
predicate = \ _ _ -> True,
|
predicate = \ _ _ -> True,
|
||||||
outputName = "divmod",
|
outputName = "divmod",
|
||||||
isUnsigned = True,
|
isUnsigned = True,
|
||||||
|
|||||||
@@ -1,136 +0,0 @@
|
|||||||
{-# LANGUAGE QuasiQuotes #-}
|
|
||||||
{-# LANGUAGE RankNTypes #-}
|
|
||||||
module File(
|
|
||||||
File(..),
|
|
||||||
Task(..),
|
|
||||||
generateTasks,
|
|
||||||
testFile
|
|
||||||
)
|
|
||||||
where
|
|
||||||
|
|
||||||
import Control.Monad(forM_)
|
|
||||||
import Data.Char(toUpper)
|
|
||||||
import Data.List(isPrefixOf)
|
|
||||||
import Data.Map.Strict(Map)
|
|
||||||
import qualified Data.Map.Strict as Map
|
|
||||||
import Language.Rust.Data.Ident(mkIdent)
|
|
||||||
import Language.Rust.Data.Position(Span)
|
|
||||||
import Language.Rust.Pretty(writeSourceFile)
|
|
||||||
import Language.Rust.Quote(item,sourceFile)
|
|
||||||
import Language.Rust.Syntax(SourceFile)
|
|
||||||
import System.FilePath(dropExtension,splitFileName,takeFileName,(</>))
|
|
||||||
import System.IO(Handle,hPutStrLn)
|
|
||||||
import System.Random(RandomGen(..))
|
|
||||||
|
|
||||||
data File = File {
|
|
||||||
predicate :: Word -> [Word] -> Bool,
|
|
||||||
outputName :: FilePath,
|
|
||||||
isUnsigned :: Bool,
|
|
||||||
generator :: Word -> [Word] -> SourceFile Span,
|
|
||||||
testCase :: forall g. RandomGen g => Maybe (Word -> g -> [Map String String])
|
|
||||||
}
|
|
||||||
|
|
||||||
data Task = Task {
|
|
||||||
outputFile :: FilePath,
|
|
||||||
writer :: Handle -> IO ()
|
|
||||||
}
|
|
||||||
|
|
||||||
testFile :: Bool -> Word -> FilePath
|
|
||||||
testFile True size = "U" ++ show5 size ++ ".test"
|
|
||||||
testFile False size = "I" ++ show5 size ++ ".test"
|
|
||||||
|
|
||||||
show5 :: Word -> String
|
|
||||||
show5 = go . show
|
|
||||||
where
|
|
||||||
go x | length x < 5 = go ('0' : x)
|
|
||||||
| otherwise = x
|
|
||||||
|
|
||||||
generateTasks :: RandomGen g => g -> [File] -> [Word] -> [Task]
|
|
||||||
generateTasks rng files sizes = basicTasks ++ moduleTasks
|
|
||||||
where
|
|
||||||
basicTasks = go rng files sizes
|
|
||||||
moduleTasks = generateModules basicTasks
|
|
||||||
--
|
|
||||||
go :: RandomGen g => g -> [File] -> [Word] -> [Task]
|
|
||||||
go _ [] _ = []
|
|
||||||
go g (_:rest) [] = go g rest sizes
|
|
||||||
go g files'@(file:_) (size:rest)
|
|
||||||
| not (predicate file size sizes) = go g files' rest
|
|
||||||
| otherwise =
|
|
||||||
let (myg, theirg) = split g
|
|
||||||
tasks = go theirg files' rest
|
|
||||||
(signedBit, prefix) | isUnsigned file = ("unsigned", "u")
|
|
||||||
| otherwise = ("signed", "i")
|
|
||||||
mainTask = Task {
|
|
||||||
outputFile = "src" </> signedBit </> (prefix ++ show size) </>
|
|
||||||
outputName file ++ ".rs",
|
|
||||||
writer = \ hndl -> writeSourceFile hndl (generator file size sizes)
|
|
||||||
}
|
|
||||||
in case testCase file of
|
|
||||||
Nothing ->
|
|
||||||
mainTask : tasks
|
|
||||||
Just caseGenerator ->
|
|
||||||
let testTask = Task {
|
|
||||||
outputFile = "testdata" </> outputName file </> testFile (isUnsigned file) size,
|
|
||||||
writer = \ hndl -> writeTestCase hndl (caseGenerator size myg)
|
|
||||||
}
|
|
||||||
in testTask : mainTask : tasks
|
|
||||||
|
|
||||||
generateModules :: [Task] -> [Task]
|
|
||||||
generateModules tasks = Map.foldrWithKey maddModule [] fileMap ++ [signedTask, unsignedTask]
|
|
||||||
where
|
|
||||||
maddModule path mods acc
|
|
||||||
| ("src/unsigned" `isPrefixOf` path) || ("src/signed" `isPrefixOf` path) =
|
|
||||||
let (basePath, lowerName) = splitFileName (init path)
|
|
||||||
upperName = map toUpper lowerName
|
|
||||||
task = Task {
|
|
||||||
outputFile = basePath </> lowerName ++ ".rs",
|
|
||||||
writer = \ hndl ->
|
|
||||||
do forM_ mods $ \ modl ->
|
|
||||||
hPutStrLn hndl ("mod " ++ modl ++ ";")
|
|
||||||
hPutStrLn hndl ("pub use base::" ++ upperName ++ ";")
|
|
||||||
}
|
|
||||||
in task : acc
|
|
||||||
| otherwise =
|
|
||||||
acc
|
|
||||||
fileMap = foldr buildBaseMap Map.empty tasks
|
|
||||||
buildBaseMap task acc =
|
|
||||||
let (dir, fileext) = splitFileName (outputFile task)
|
|
||||||
file = dropExtension fileext
|
|
||||||
in Map.insertWith (++) dir [file] acc
|
|
||||||
--
|
|
||||||
signedTask = moduleTask "signed"
|
|
||||||
unsignedTask = moduleTask "unsigned"
|
|
||||||
moduleTask kind =
|
|
||||||
let mods = Map.foldrWithKey (topModule kind) [] fileMap
|
|
||||||
pubuses = Map.foldrWithKey (pubUse kind) [] fileMap
|
|
||||||
in Task {
|
|
||||||
outputFile = "src" </> (kind ++ ".rs"),
|
|
||||||
writer = \ hndl ->
|
|
||||||
writeSourceFile hndl [sourceFile|
|
|
||||||
$@{mods}
|
|
||||||
$@{pubuses}
|
|
||||||
|]
|
|
||||||
}
|
|
||||||
topModule kind path _ acc
|
|
||||||
| ("src/" ++ kind) `isPrefixOf` path =
|
|
||||||
let lowerName = takeFileName (init path)
|
|
||||||
modl = mkIdent lowerName
|
|
||||||
in [item| mod $$modl; |] : acc
|
|
||||||
| otherwise =
|
|
||||||
acc
|
|
||||||
pubUse kind path _ acc
|
|
||||||
| ("src/" ++ kind) `isPrefixOf` path =
|
|
||||||
let lowerName = takeFileName (init path)
|
|
||||||
tname = mkIdent (map toUpper lowerName)
|
|
||||||
modl = mkIdent lowerName
|
|
||||||
in [item| pub use $$modl::$$tname; |] : acc
|
|
||||||
| otherwise =
|
|
||||||
acc
|
|
||||||
|
|
||||||
|
|
||||||
writeTestCase :: Handle -> [Map String String] -> IO ()
|
|
||||||
writeTestCase hndl tests =
|
|
||||||
forM_ tests $ \ test ->
|
|
||||||
forM_ (Map.toList test) $ \ (key, value) ->
|
|
||||||
hPutStrLn hndl (key ++ ": " ++ value)
|
|
||||||
@@ -8,20 +8,20 @@ module ModInv(
|
|||||||
import Control.Exception(assert)
|
import Control.Exception(assert)
|
||||||
import Data.Map.Strict(Map)
|
import Data.Map.Strict(Map)
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import File
|
|
||||||
import Generators
|
import Generators
|
||||||
import GHC.Integer.GMP.Internals(recipModInteger)
|
import GHC.Integer.GMP.Internals(recipModInteger)
|
||||||
import Language.Rust.Data.Ident
|
import Language.Rust.Data.Ident
|
||||||
import Language.Rust.Data.Position
|
import Language.Rust.Data.Position
|
||||||
import Language.Rust.Quote
|
import Language.Rust.Quote
|
||||||
import Language.Rust.Syntax
|
import Language.Rust.Syntax
|
||||||
|
import RustModule
|
||||||
import System.Random(RandomGen)
|
import System.Random(RandomGen)
|
||||||
|
|
||||||
numTestCases :: Int
|
numTestCases :: Int
|
||||||
numTestCases = 100
|
numTestCases = 100
|
||||||
|
|
||||||
generateModInvOps :: File
|
generateModInvOps :: RustModule
|
||||||
generateModInvOps = File {
|
generateModInvOps = RustModule {
|
||||||
predicate = \ me others -> (me + 64) `elem` others,
|
predicate = \ me others -> (me + 64) `elem` others,
|
||||||
outputName = "modinv",
|
outputName = "modinv",
|
||||||
isUnsigned = True,
|
isUnsigned = True,
|
||||||
|
|||||||
@@ -4,20 +4,20 @@ module ModOps(modulusOps)
|
|||||||
|
|
||||||
import Data.Map.Strict(Map)
|
import Data.Map.Strict(Map)
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import File
|
|
||||||
import Generators
|
import Generators
|
||||||
import GHC.Integer.GMP.Internals(powModInteger)
|
import GHC.Integer.GMP.Internals(powModInteger)
|
||||||
import Language.Rust.Data.Ident
|
import Language.Rust.Data.Ident
|
||||||
import Language.Rust.Data.Position
|
import Language.Rust.Data.Position
|
||||||
import Language.Rust.Quote
|
import Language.Rust.Quote
|
||||||
import Language.Rust.Syntax
|
import Language.Rust.Syntax
|
||||||
|
import RustModule
|
||||||
import System.Random(RandomGen)
|
import System.Random(RandomGen)
|
||||||
|
|
||||||
numTestCases :: Int
|
numTestCases :: Int
|
||||||
numTestCases = 1000
|
numTestCases = 1000
|
||||||
|
|
||||||
modulusOps :: File
|
modulusOps :: RustModule
|
||||||
modulusOps = File {
|
modulusOps = RustModule {
|
||||||
predicate = \ me others -> (me * 2) `elem` others,
|
predicate = \ me others -> (me * 2) `elem` others,
|
||||||
outputName = "modops",
|
outputName = "modops",
|
||||||
isUnsigned = True,
|
isUnsigned = True,
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import Data.Bits((.&.))
|
|||||||
import Data.List(union)
|
import Data.List(union)
|
||||||
import Data.Map.Strict(Map)
|
import Data.Map.Strict(Map)
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import File
|
|
||||||
import Gen(toLit)
|
import Gen(toLit)
|
||||||
import Generators
|
import Generators
|
||||||
import Karatsuba
|
import Karatsuba
|
||||||
@@ -17,13 +16,14 @@ import Language.Rust.Data.Ident
|
|||||||
import Language.Rust.Data.Position
|
import Language.Rust.Data.Position
|
||||||
import Language.Rust.Quote
|
import Language.Rust.Quote
|
||||||
import Language.Rust.Syntax
|
import Language.Rust.Syntax
|
||||||
|
import RustModule
|
||||||
import System.Random(RandomGen)
|
import System.Random(RandomGen)
|
||||||
|
|
||||||
numTestCases :: Int
|
numTestCases :: Int
|
||||||
numTestCases = 3000
|
numTestCases = 3000
|
||||||
|
|
||||||
safeMultiplyOps :: File
|
safeMultiplyOps :: RustModule
|
||||||
safeMultiplyOps = File {
|
safeMultiplyOps = RustModule {
|
||||||
predicate = \ me others -> (me * 2) `elem` others,
|
predicate = \ me others -> (me * 2) `elem` others,
|
||||||
outputName = "safe_mul",
|
outputName = "safe_mul",
|
||||||
isUnsigned = True,
|
isUnsigned = True,
|
||||||
@@ -31,8 +31,8 @@ safeMultiplyOps = File {
|
|||||||
testCase = Just generateSafeTests
|
testCase = Just generateSafeTests
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafeMultiplyOps :: File
|
unsafeMultiplyOps :: RustModule
|
||||||
unsafeMultiplyOps = File {
|
unsafeMultiplyOps = RustModule {
|
||||||
predicate = \ _ _ -> True,
|
predicate = \ _ _ -> True,
|
||||||
outputName = "unsafe_mul",
|
outputName = "unsafe_mul",
|
||||||
isUnsigned = True,
|
isUnsigned = True,
|
||||||
|
|||||||
191
generation/src/RustModule.hs
Normal file
191
generation/src/RustModule.hs
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
|
{-# LANGUAGE RankNTypes #-}
|
||||||
|
module RustModule(
|
||||||
|
RustModule(..),
|
||||||
|
Task(..),
|
||||||
|
generateTasks,
|
||||||
|
testFile
|
||||||
|
)
|
||||||
|
where
|
||||||
|
|
||||||
|
import Control.Monad(forM_)
|
||||||
|
import Data.Char(toUpper)
|
||||||
|
import Data.List(isPrefixOf, partition)
|
||||||
|
import Data.Map.Strict(Map)
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
|
import Data.Maybe(mapMaybe)
|
||||||
|
import Language.Rust.Data.Ident(mkIdent)
|
||||||
|
import Language.Rust.Data.Position(Span, spanOf)
|
||||||
|
import Language.Rust.Pretty(writeSourceFile)
|
||||||
|
import Language.Rust.Quote(item, sourceFile)
|
||||||
|
import Language.Rust.Syntax(Item(..), SourceFile(..), Visibility(..))
|
||||||
|
import System.IO(Handle,hPutStrLn)
|
||||||
|
import System.Random(RandomGen(..))
|
||||||
|
|
||||||
|
data RustModule = RustModule {
|
||||||
|
predicate :: Word -> [Word] -> Bool,
|
||||||
|
outputName :: String,
|
||||||
|
isUnsigned :: Bool,
|
||||||
|
generator :: Word -> [Word] -> SourceFile Span,
|
||||||
|
testCase :: forall g. RandomGen g => Maybe (Word -> g -> [Map String String])
|
||||||
|
}
|
||||||
|
|
||||||
|
data Task = Task {
|
||||||
|
outputFile :: FilePath,
|
||||||
|
writer :: Handle -> IO ()
|
||||||
|
}
|
||||||
|
|
||||||
|
testFile :: Bool -> Word -> FilePath
|
||||||
|
testFile True size = "U" ++ show5 size ++ ".test"
|
||||||
|
testFile False size = "I" ++ show5 size ++ ".test"
|
||||||
|
|
||||||
|
show5 :: Word -> String
|
||||||
|
show5 = go . show
|
||||||
|
where
|
||||||
|
go x | length x < 5 = go ('0' : x)
|
||||||
|
| otherwise = x
|
||||||
|
|
||||||
|
generateTasks :: RandomGen g => g -> [RustModule] -> [Word] -> [Task]
|
||||||
|
generateTasks rng modules sizes = allTheFiles
|
||||||
|
where
|
||||||
|
allTheFiles = implementationsAndTests ++
|
||||||
|
[lump "src/signed", lump "src/unsigned"]
|
||||||
|
implementationsAndTests = concatMap generateModules sizes
|
||||||
|
--
|
||||||
|
lump prefix =
|
||||||
|
let allFiles = map outputFile implementationsAndTests
|
||||||
|
files = filter (prefix `isPrefixOf`) allFiles
|
||||||
|
moduleFiles = map (drop (length prefix + 1)) files
|
||||||
|
moduleNames = map (takeWhile (/= '.')) moduleFiles
|
||||||
|
moduleIdents = map mkIdent moduleNames
|
||||||
|
types = map (mkIdent . map toUpper) moduleNames
|
||||||
|
mods = map (\ name -> [item| mod $$name; |]) moduleIdents
|
||||||
|
uses = zipWith (\ mname tname -> [item| pub use $$mname::$$tname; |])
|
||||||
|
moduleIdents types
|
||||||
|
file = [sourceFile| $@{mods} $@{uses} |]
|
||||||
|
in Task (prefix ++ ".rs") (\hndl -> writeSourceFile hndl file)
|
||||||
|
--
|
||||||
|
generateModules size =
|
||||||
|
let modules' = filter (\m -> predicate m size sizes) modules
|
||||||
|
(umodules, smodules) = partition isUnsigned modules'
|
||||||
|
unsignedTasks = generateImplementations "U" size umodules
|
||||||
|
signedTasks = generateImplementations "I" size smodules
|
||||||
|
in unsignedTasks ++ signedTasks ++ mapMaybe (generateTests size rng) modules'
|
||||||
|
--
|
||||||
|
generateImplementations startsWith size modules'
|
||||||
|
| null modules' = []
|
||||||
|
| otherwise =
|
||||||
|
let name = mkIdent (startsWith ++ show size)
|
||||||
|
baseInclude = [item| pub use self::base::$$name; |]
|
||||||
|
moduleSources = map (generateSubmodule size sizes) modules'
|
||||||
|
moduleFile | startsWith == "I" = "src/signed/i" ++ show size ++ ".rs"
|
||||||
|
| otherwise = "src/unsigned/u" ++ show size ++ ".rs"
|
||||||
|
allSource = SourceFile Nothing [] (baseInclude : moduleSources)
|
||||||
|
in [Task moduleFile (\ hndl -> writeSourceFile hndl allSource)]
|
||||||
|
|
||||||
|
generateSubmodule :: Word -> [Word] -> RustModule -> Item Span
|
||||||
|
generateSubmodule size allSizes m =
|
||||||
|
let SourceFile _ attrs internals = generator m size allSizes
|
||||||
|
modName = mkIdent (outputName m)
|
||||||
|
modSpan = spanOf internals
|
||||||
|
in Mod attrs CrateV modName (Just internals) modSpan
|
||||||
|
|
||||||
|
generateTests :: RandomGen g =>
|
||||||
|
Word -> g ->
|
||||||
|
RustModule ->
|
||||||
|
Maybe Task
|
||||||
|
generateTests size rng m = fmap builder (testCase m)
|
||||||
|
where
|
||||||
|
builder testGeneration =
|
||||||
|
let outFile = "testdata/" ++ outputName m ++ "/" ++ testFile (isUnsigned m) size
|
||||||
|
testGenAction hndl = writeTestCase hndl (testGeneration size (snd (split rng)))
|
||||||
|
in Task outFile testGenAction
|
||||||
|
|
||||||
|
-- basicTasks ++ moduleTasks
|
||||||
|
-- where
|
||||||
|
-- basicTasks = go rng files sizes
|
||||||
|
-- moduleTasks = generateModules basicTasks
|
||||||
|
-- --
|
||||||
|
-- go :: RandomGen g => g -> [RustModule] -> [Word] -> [Task]
|
||||||
|
-- go _ [] _ = []
|
||||||
|
-- go g (_:rest) [] = go g rest sizes
|
||||||
|
-- go g files'@(file:_) (size:rest)
|
||||||
|
-- | not (predicate file size sizes) = go g files' rest
|
||||||
|
-- | otherwise =
|
||||||
|
-- let (myg, theirg) = split g
|
||||||
|
-- tasks = go theirg files' rest
|
||||||
|
-- (signedBit, prefix) | isUnsigned file = ("unsigned", "u")
|
||||||
|
-- | otherwise = ("signed", "i")
|
||||||
|
-- mainTask = Task {
|
||||||
|
-- outputFile = "src" </> signedBit </> (prefix ++ show size) </>
|
||||||
|
-- outputName file ++ ".rs",
|
||||||
|
-- writer = \ hndl -> writeSourceFile hndl (generator file size sizes)
|
||||||
|
-- }
|
||||||
|
-- in case testCase file of
|
||||||
|
-- Nothing ->
|
||||||
|
-- mainTask : tasks
|
||||||
|
-- Just caseGenerator ->
|
||||||
|
-- let testTask = Task {
|
||||||
|
-- outputFile = "testdata" </> outputName file </> testFile (isUnsigned file) size,
|
||||||
|
-- writer = \ hndl -> writeTestCase hndl (caseGenerator size myg)
|
||||||
|
-- }
|
||||||
|
-- in testTask : mainTask : tasks
|
||||||
|
--
|
||||||
|
--generateModules :: [Task] -> [Task]
|
||||||
|
--generateModules tasks = Map.foldrWithKey maddModule [] fileMap ++ [signedTask, unsignedTask]
|
||||||
|
-- where
|
||||||
|
-- maddModule path mods acc
|
||||||
|
-- | ("src/unsigned" `isPrefixOf` path) || ("src/signed" `isPrefixOf` path) =
|
||||||
|
-- let (basePath, lowerName) = splitFileName (init path)
|
||||||
|
-- upperName = map toUpper lowerName
|
||||||
|
-- task = Task {
|
||||||
|
-- outputFile = basePath </> lowerName ++ ".rs",
|
||||||
|
-- writer = \ hndl ->
|
||||||
|
-- do forM_ mods $ \ modl ->
|
||||||
|
-- hPutStrLn hndl ("mod " ++ modl ++ ";")
|
||||||
|
-- hPutStrLn hndl ("pub use base::" ++ upperName ++ ";")
|
||||||
|
-- }
|
||||||
|
-- in task : acc
|
||||||
|
-- | otherwise =
|
||||||
|
-- acc
|
||||||
|
-- fileMap = foldr buildBaseMap Map.empty tasks
|
||||||
|
-- buildBaseMap task acc =
|
||||||
|
-- let (dir, fileext) = splitFileName (outputFile task)
|
||||||
|
-- file = dropExtension fileext
|
||||||
|
-- in Map.insertWith (++) dir [file] acc
|
||||||
|
-- --
|
||||||
|
-- signedTask = moduleTask "signed"
|
||||||
|
-- unsignedTask = moduleTask "unsigned"
|
||||||
|
-- moduleTask kind =
|
||||||
|
-- let mods = Map.foldrWithKey (topModule kind) [] fileMap
|
||||||
|
-- pubuses = Map.foldrWithKey (pubUse kind) [] fileMap
|
||||||
|
-- in Task {
|
||||||
|
-- outputFile = "src" </> (kind ++ ".rs"),
|
||||||
|
-- writer = \ hndl ->
|
||||||
|
-- writeSourceFile hndl [sourceFile|
|
||||||
|
-- $@{mods}
|
||||||
|
-- $@{pubuses}
|
||||||
|
-- |]
|
||||||
|
-- }
|
||||||
|
-- topModule kind path _ acc
|
||||||
|
-- | ("src/" ++ kind) `isPrefixOf` path =
|
||||||
|
-- let lowerName = takeFileName (init path)
|
||||||
|
-- modl = mkIdent lowerName
|
||||||
|
-- in [item| mod $$modl; |] : acc
|
||||||
|
-- | otherwise =
|
||||||
|
-- acc
|
||||||
|
-- pubUse kind path _ acc
|
||||||
|
-- | ("src/" ++ kind) `isPrefixOf` path =
|
||||||
|
-- let lowerName = takeFileName (init path)
|
||||||
|
-- tname = mkIdent (map toUpper lowerName)
|
||||||
|
-- modl = mkIdent lowerName
|
||||||
|
-- in [item| pub use $$modl::$$tname; |] : acc
|
||||||
|
-- | otherwise =
|
||||||
|
-- acc
|
||||||
|
--
|
||||||
|
--
|
||||||
|
writeTestCase :: Handle -> [Map String String] -> IO ()
|
||||||
|
writeTestCase hndl tests =
|
||||||
|
forM_ tests $ \ test ->
|
||||||
|
forM_ (Map.toList test) $ \ (key, value) ->
|
||||||
|
hPutStrLn hndl (key ++ ": " ++ value)
|
||||||
@@ -8,20 +8,20 @@ module Scale(
|
|||||||
import Data.Bits((.&.))
|
import Data.Bits((.&.))
|
||||||
import Data.Map.Strict(Map)
|
import Data.Map.Strict(Map)
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import File
|
|
||||||
import Gen(toLit)
|
import Gen(toLit)
|
||||||
import Generators
|
import Generators
|
||||||
import Language.Rust.Data.Ident
|
import Language.Rust.Data.Ident
|
||||||
import Language.Rust.Data.Position
|
import Language.Rust.Data.Position
|
||||||
import Language.Rust.Quote
|
import Language.Rust.Quote
|
||||||
import Language.Rust.Syntax
|
import Language.Rust.Syntax
|
||||||
|
import RustModule
|
||||||
import System.Random(RandomGen)
|
import System.Random(RandomGen)
|
||||||
|
|
||||||
numTestCases :: Int
|
numTestCases :: Int
|
||||||
numTestCases = 3000
|
numTestCases = 3000
|
||||||
|
|
||||||
safeScaleOps :: File
|
safeScaleOps :: RustModule
|
||||||
safeScaleOps = File {
|
safeScaleOps = RustModule {
|
||||||
predicate = \ me others -> (me + 64) `elem` others,
|
predicate = \ me others -> (me + 64) `elem` others,
|
||||||
outputName = "safe_scale",
|
outputName = "safe_scale",
|
||||||
isUnsigned = True,
|
isUnsigned = True,
|
||||||
@@ -29,8 +29,8 @@ safeScaleOps = File {
|
|||||||
testCase = Just generateSafeTests
|
testCase = Just generateSafeTests
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafeScaleOps :: File
|
unsafeScaleOps :: RustModule
|
||||||
unsafeScaleOps = File {
|
unsafeScaleOps = RustModule {
|
||||||
predicate = \ _ _ -> True,
|
predicate = \ _ _ -> True,
|
||||||
outputName = "unsafe_scale",
|
outputName = "unsafe_scale",
|
||||||
isUnsigned = True,
|
isUnsigned = True,
|
||||||
|
|||||||
@@ -5,20 +5,20 @@ module Shift(shiftOps, signedShiftOps)
|
|||||||
import Data.Bits(shiftL,shiftR)
|
import Data.Bits(shiftL,shiftR)
|
||||||
import Data.Map.Strict(Map)
|
import Data.Map.Strict(Map)
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import File
|
|
||||||
import Gen(toLit)
|
import Gen(toLit)
|
||||||
import Generators
|
import Generators
|
||||||
import Language.Rust.Data.Ident
|
import Language.Rust.Data.Ident
|
||||||
import Language.Rust.Data.Position
|
import Language.Rust.Data.Position
|
||||||
import Language.Rust.Quote
|
import Language.Rust.Quote
|
||||||
import Language.Rust.Syntax
|
import Language.Rust.Syntax
|
||||||
|
import RustModule
|
||||||
import System.Random(RandomGen)
|
import System.Random(RandomGen)
|
||||||
|
|
||||||
numTestCases :: Int
|
numTestCases :: Int
|
||||||
numTestCases = 3000
|
numTestCases = 3000
|
||||||
|
|
||||||
shiftOps :: File
|
shiftOps :: RustModule
|
||||||
shiftOps = File {
|
shiftOps = RustModule {
|
||||||
predicate = \ _ _ -> True,
|
predicate = \ _ _ -> True,
|
||||||
outputName = "shift",
|
outputName = "shift",
|
||||||
isUnsigned = True,
|
isUnsigned = True,
|
||||||
@@ -26,8 +26,8 @@ shiftOps = File {
|
|||||||
testCase = Just generateTests
|
testCase = Just generateTests
|
||||||
}
|
}
|
||||||
|
|
||||||
signedShiftOps :: File
|
signedShiftOps :: RustModule
|
||||||
signedShiftOps = File {
|
signedShiftOps = RustModule {
|
||||||
predicate = \ _ _ -> True,
|
predicate = \ _ _ -> True,
|
||||||
outputName = "sshift",
|
outputName = "sshift",
|
||||||
isUnsigned = False,
|
isUnsigned = False,
|
||||||
|
|||||||
@@ -2,15 +2,14 @@
|
|||||||
module Signed(signedBaseOps)
|
module Signed(signedBaseOps)
|
||||||
where
|
where
|
||||||
|
|
||||||
import File
|
|
||||||
import Language.Rust.Data.Ident
|
import Language.Rust.Data.Ident
|
||||||
import Language.Rust.Data.Position
|
import Language.Rust.Data.Position
|
||||||
import Language.Rust.Quote
|
import Language.Rust.Quote
|
||||||
import Language.Rust.Syntax
|
import Language.Rust.Syntax
|
||||||
|
import RustModule
|
||||||
|
|
||||||
|
signedBaseOps :: RustModule
|
||||||
signedBaseOps :: File
|
signedBaseOps = RustModule {
|
||||||
signedBaseOps = File {
|
|
||||||
predicate = const (const True),
|
predicate = const (const True),
|
||||||
outputName = "base",
|
outputName = "base",
|
||||||
isUnsigned = False,
|
isUnsigned = False,
|
||||||
|
|||||||
@@ -10,20 +10,20 @@ module Subtract(
|
|||||||
import Data.Bits((.&.))
|
import Data.Bits((.&.))
|
||||||
import Data.Map.Strict(Map)
|
import Data.Map.Strict(Map)
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import File
|
|
||||||
import Gen(toLit)
|
import Gen(toLit)
|
||||||
import Generators
|
import Generators
|
||||||
import Language.Rust.Data.Ident
|
import Language.Rust.Data.Ident
|
||||||
import Language.Rust.Data.Position
|
import Language.Rust.Data.Position
|
||||||
import Language.Rust.Quote
|
import Language.Rust.Quote
|
||||||
import Language.Rust.Syntax
|
import Language.Rust.Syntax
|
||||||
|
import RustModule
|
||||||
import System.Random(RandomGen)
|
import System.Random(RandomGen)
|
||||||
|
|
||||||
numTestCases :: Int
|
numTestCases :: Int
|
||||||
numTestCases = 3000
|
numTestCases = 3000
|
||||||
|
|
||||||
safeSubtractOps :: File
|
safeSubtractOps :: RustModule
|
||||||
safeSubtractOps = File {
|
safeSubtractOps = RustModule {
|
||||||
predicate = \ me others -> (me + 64) `elem` others,
|
predicate = \ me others -> (me + 64) `elem` others,
|
||||||
outputName = "safe_sub",
|
outputName = "safe_sub",
|
||||||
isUnsigned = True,
|
isUnsigned = True,
|
||||||
@@ -31,8 +31,8 @@ safeSubtractOps = File {
|
|||||||
testCase = Just generateSafeTests
|
testCase = Just generateSafeTests
|
||||||
}
|
}
|
||||||
|
|
||||||
safeSignedSubtractOps :: File
|
safeSignedSubtractOps :: RustModule
|
||||||
safeSignedSubtractOps = File {
|
safeSignedSubtractOps = RustModule {
|
||||||
predicate = \ me others -> (me + 64) `elem` others,
|
predicate = \ me others -> (me + 64) `elem` others,
|
||||||
outputName = "safe_ssub",
|
outputName = "safe_ssub",
|
||||||
isUnsigned = False,
|
isUnsigned = False,
|
||||||
@@ -40,8 +40,8 @@ safeSignedSubtractOps = File {
|
|||||||
testCase = Just generateSafeSignedTests
|
testCase = Just generateSafeSignedTests
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafeSubtractOps :: File
|
unsafeSubtractOps :: RustModule
|
||||||
unsafeSubtractOps = File {
|
unsafeSubtractOps = RustModule {
|
||||||
predicate = \ _ _ -> True,
|
predicate = \ _ _ -> True,
|
||||||
outputName = "unsafe_sub",
|
outputName = "unsafe_sub",
|
||||||
isUnsigned = True,
|
isUnsigned = True,
|
||||||
@@ -49,8 +49,8 @@ unsafeSubtractOps = File {
|
|||||||
testCase = Just generateUnsafeTests
|
testCase = Just generateUnsafeTests
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafeSignedSubtractOps :: File
|
unsafeSignedSubtractOps :: RustModule
|
||||||
unsafeSignedSubtractOps = File {
|
unsafeSignedSubtractOps = RustModule {
|
||||||
predicate = \ _ _ -> True,
|
predicate = \ _ _ -> True,
|
||||||
outputName = "unsafe_ssub",
|
outputName = "unsafe_ssub",
|
||||||
isUnsigned = False,
|
isUnsigned = False,
|
||||||
|
|||||||
Reference in New Issue
Block a user