aboutsummaryrefslogtreecommitdiffstats
path: root/src/Verismith/Reduce.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Verismith/Reduce.hs')
-rw-r--r--src/Verismith/Reduce.hs875
1 files changed, 491 insertions, 384 deletions
diff --git a/src/Verismith/Reduce.hs b/src/Verismith/Reduce.hs
index 3ea25a2..6df398d 100644
--- a/src/Verismith/Reduce.hs
+++ b/src/Verismith/Reduce.hs
@@ -1,67 +1,69 @@
-{-|
-Module : Verismith.Reduce
-Description : Test case reducer implementation.
-Copyright : (c) 2019, Yann Herklotz
-License : GPL-3
-Maintainer : yann [at] yannherklotz [dot] com
-Stability : experimental
-Portability : POSIX
-
-Test case reducer implementation.
--}
-
-{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
+-- |
+-- Module : Verismith.Reduce
+-- Description : Test case reducer implementation.
+-- Copyright : (c) 2019, Yann Herklotz
+-- License : GPL-3
+-- Maintainer : yann [at] yannherklotz [dot] com
+-- Stability : experimental
+-- Portability : POSIX
+--
+-- Test case reducer implementation.
module Verismith.Reduce
- ( -- $strategy
- reduceWithScript
- , reduceSynth
- , reduceSynthesis
- , reduceSimIc
- , reduce
- , reduce_
- , Replacement(..)
- , halveModules
- , halveModItems
- , halveStatements
- , halveExpr
- , halveAssigns
- , findActiveWires
- , clean
- , cleanSourceInfo
- , cleanSourceInfoAll
- , removeDecl
- , removeConstInConcat
- , takeReplace
- , filterExpr
- )
+ ( -- $strategy
+ reduceWithScript,
+ reduceSynth,
+ reduceSynthesis,
+ reduceSimIc,
+ reduce,
+ reduce_,
+ Replacement (..),
+ halveModules,
+ halveModItems,
+ halveStatements,
+ halveExpr,
+ halveAssigns,
+ findActiveWires,
+ clean,
+ cleanSourceInfo,
+ cleanSourceInfoAll,
+ removeDecl,
+ removeConstInConcat,
+ takeReplace,
+ filterExpr,
+ ReduceAnn (..),
+ tagAlways,
+ untagAlways,
+ )
where
-import Control.Lens hiding ((<.>))
-import Control.Monad (void)
-import Control.Monad.IO.Class (MonadIO, liftIO)
-import Data.ByteString (ByteString)
-import Data.Foldable (foldrM)
-import Data.List (nub)
-import Data.List.NonEmpty (NonEmpty (..))
-import qualified Data.List.NonEmpty as NonEmpty
-import Data.Maybe (mapMaybe)
-import Data.Text (Text)
-import Shelly (fromText, (<.>))
+import Control.Lens hiding ((<.>))
+import Control.Monad (void)
+import Control.Monad.IO.Class (MonadIO, liftIO)
+import Data.ByteString (ByteString)
+import Data.Foldable (foldrM)
+import Data.IORef (newIORef, readIORef, writeIORef)
+import Data.List (nub)
+import Data.List.NonEmpty (NonEmpty (..))
+import qualified Data.List.NonEmpty as NonEmpty
+import Data.Maybe (mapMaybe)
+import Data.Text (Text, unpack)
+import Shelly ((<.>), fromText)
import qualified Shelly
-import Shelly.Lifted (MonadSh, liftSh, rm_rf, writefile)
-import Verismith.Internal
-import Verismith.Result
-import Verismith.Tool
-import Verismith.Tool.Icarus
-import Verismith.Tool.Identity
-import Verismith.Tool.Internal
-import Verismith.Verilog
-import Verismith.Verilog.AST
-import Verismith.Verilog.Mutate
-import Verismith.Verilog.Parser
-
+import Shelly.Lifted (MonadSh, liftSh, rm_rf, writefile)
+import Verismith.Internal
+import Verismith.Result
+import Verismith.Tool
+import Verismith.Tool.Icarus
+import Verismith.Tool.Identity
+import Verismith.Tool.Internal
+import Verismith.Verilog
+import Verismith.Verilog.AST
+import Verismith.Verilog.CodeGen
+import Verismith.Verilog.Mutate
+import Verismith.Verilog.Parser
-- $strategy
-- The reduction strategy has multiple different steps. 'reduce' will run these
@@ -86,49 +88,61 @@ import Verismith.Verilog.Parser
-- | Replacement type that supports returning different kinds of reduced
-- replacements that could be tried.
-data Replacement a = Dual a a
- | Single a
- | None
- deriving (Show, Eq)
+data Replacement a
+ = Dual a a
+ | Single a
+ | None
+ deriving (Show, Eq)
-type Replace a = a -> Replacement a
+data ReduceAnn
+ = Active
+ | Reduced
+ | Idle
+ deriving (Show, Eq)
+
+type Replace a = (a -> Replacement a)
instance Functor Replacement where
- fmap f (Dual a b) = Dual (f a) $ f b
- fmap f (Single a) = Single $ f a
- fmap _ None = None
+ fmap f (Dual a b) = Dual (f a) $ f b
+ fmap f (Single a) = Single $ f a
+ fmap _ None = None
instance Applicative Replacement where
- pure = Single
- (Dual a b) <*> (Dual c d) = Dual (a c) $ b d
- (Dual a b) <*> (Single c) = Dual (a c) $ b c
- (Single a) <*> (Dual b c) = Dual (a b) $ a c
- (Single a) <*> (Single b) = Single $ a b
- None <*> _ = None
- _ <*> None = None
+ pure = Single
+ (Dual a b) <*> (Dual c d) = Dual (a c) $ b d
+ (Dual a b) <*> (Single c) = Dual (a c) $ b c
+ (Single a) <*> (Dual b c) = Dual (a b) $ a c
+ (Single a) <*> (Single b) = Single $ a b
+ None <*> _ = None
+ _ <*> None = None
instance Foldable Replacement where
- foldMap _ None = mempty
- foldMap f (Single a) = f a
- foldMap f (Dual a b) = f a <> f b
+ foldMap _ None = mempty
+ foldMap f (Single a) = f a
+ foldMap f (Dual a b) = f a <> f b
instance Traversable Replacement where
- traverse _ None = pure None
- traverse f (Single a) = Single <$> f a
- traverse f (Dual a b) = Dual <$> f a <*> f b
+ traverse _ None = pure None
+ traverse f (Single a) = Single <$> f a
+ traverse f (Dual a b) = Dual <$> f a <*> f b
-- | Split a list in two halves.
halve :: Replace [a]
-halve [] = Single []
+halve [] = Single []
halve [_] = Single []
-halve l = Dual a b where (a, b) = splitAt (length l `div` 2) l
+halve l = Dual a b where (a, b) = splitAt (length l `div` 2) l
+
+remove1 :: Replace [a]
+remove1 [] = Single []
+remove1 [_] = Single []
+remove1 (a : b) = Dual [a] b
halveNonEmpty :: Replace (NonEmpty a)
halveNonEmpty l = case NonEmpty.splitAt (length l `div` 2) l of
- ([] , [] ) -> None
- ([] , a : b) -> Single $ a :| b
- (a : b, [] ) -> Single $ a :| b
- (a : b, c : d) -> Dual (a :| b) $ c :| d
+ ([], []) -> None
+ ([], a : b) -> Single $ a :| b
+ (a : b, []) -> Single $ a :| b
+ (a : b, c : d) -> Dual (a :| b) $ c :| d
-- | When given a Lens and a function that works on a lower replacement, it will
-- go down, apply the replacement, and return a replacement of the original
@@ -147,22 +161,22 @@ combineL l f i = modify <$> f (i ^. l) where modify res = i & l .~ res
filterExpr :: [Identifier] -> Expr -> Expr
filterExpr ids (Id i) = if i `elem` ids then Id i else Number 0
filterExpr ids (VecSelect i e) =
- if i `elem` ids then VecSelect i e else Number 0
+ if i `elem` ids then VecSelect i e else Number 0
filterExpr ids (RangeSelect i r) =
- if i `elem` ids then RangeSelect i r else Number 0
+ if i `elem` ids then RangeSelect i r else Number 0
filterExpr _ e = e
-- | Checks if a declaration is part of the current scope. If not, it returns
-- 'False', otherwise 'True', as it should be kept.
---filterDecl :: [Identifier] -> (ModItem ann) -> Bool
---filterDecl ids (Decl Nothing (Port _ _ _ i) _) = i `elem` ids
---filterDecl _ _ = True
+-- filterDecl :: [Identifier] -> (ModItem ReduceAnn) -> Bool
+-- filterDecl ids (Decl Nothing (Port _ _ _ i) _) = i `elem` ids
+-- filterDecl _ _ = True
-- | Checks if a continuous assignment is in the current scope, if not, it
-- returns 'False'.
-filterAssigns :: [Port] -> (ModItem ann) -> Bool
+filterAssigns :: [Port] -> (ModItem ReduceAnn) -> Bool
filterAssigns out (ModCA (ContAssign i _)) =
- elem i $ out ^.. traverse . portName
+ elem i $ out ^.. traverse . portName
filterAssigns _ _ = True
clean :: (Mutate a) => [Identifier] -> a -> a
@@ -171,123 +185,104 @@ clean ids = mutExpr (transform $ filterExpr ids)
takeReplace :: (Monoid a) => Replacement a -> a
takeReplace (Single a) = a
takeReplace (Dual a _) = a
-takeReplace None = mempty
+takeReplace None = mempty
-removeConstInConcat :: Replace (SourceInfo ann)
+-- | Remove all the constants that are in the concatination.
+removeConstInConcat :: Replace (SourceInfo ReduceAnn)
removeConstInConcat = Single . mutExpr replace
where
replace :: Expr -> Expr
- replace (Concat expr) = maybe (Number 0) Concat . NonEmpty.nonEmpty
- $ NonEmpty.filter notConstant expr
- replace e = e
+ replace (Concat expr) =
+ maybe (Number 0) Concat . NonEmpty.nonEmpty $
+ NonEmpty.filter notConstant expr
+ replace e = e
notConstant (Number _) = False
- notConstant _ = True
+ notConstant _ = True
-cleanUndefined :: [Identifier] -> [ModItem ann] -> [ModItem ann]
+cleanUndefined :: [Identifier] -> [ModItem ReduceAnn] -> [ModItem ReduceAnn]
cleanUndefined ids mis = clean usedWires mis
where
usedWires = mis ^.. traverse . modContAssign . contAssignNetLVal <> ids
-halveModAssign :: Replace (ModDecl ann)
+halveModAssign :: Replace (ModDecl ReduceAnn)
halveModAssign m = cleanMod m $ modify <$> assigns (m ^. modItems)
where
assigns = halve . filter (filterAssigns $ m ^. modOutPorts)
modify l = m & modItems .~ l
-cleanMod :: (ModDecl ann) -> Replacement (ModDecl ann) -> Replacement (ModDecl ann)
+cleanMod :: (ModDecl ReduceAnn) -> Replacement (ModDecl ReduceAnn) -> Replacement (ModDecl ReduceAnn)
cleanMod m newm = modify . change <$> newm
where
mis = m ^. modItems
modify l = m & modItems .~ l
change l =
- cleanUndefined (m ^.. modInPorts . traverse . portName)
- . combineAssigns (head $ m ^. modOutPorts)
- . (filter (not . filterAssigns []) mis <>)
- $ l
- ^. modItems
+ cleanUndefined (m ^.. modInPorts . traverse . portName)
+ . combineAssigns (head $ m ^. modOutPorts)
+ . (filter (not . filterAssigns []) mis <>)
+ $ l
+ ^. modItems
halveIndExpr :: Replace Expr
-halveIndExpr (Concat l ) = Concat <$> halveNonEmpty l
-halveIndExpr (BinOp e1 _ e2) = Dual e1 e2
-halveIndExpr (Cond _ e1 e2) = Dual e1 e2
-halveIndExpr (UnOp _ e ) = Single e
-halveIndExpr (Appl _ e ) = Single e
-halveIndExpr e = Single e
-
-halveModExpr :: Replace (ModItem ann)
+halveIndExpr (Concat l) = Concat <$> halveNonEmpty l
+halveIndExpr (BinOp e1 _ e2) = Dual e1 e2
+halveIndExpr (Cond _ e1 e2) = Dual e1 e2
+halveIndExpr (UnOp _ e) = Single e
+halveIndExpr (Appl _ e) = Single e
+halveIndExpr e = Single e
+
+halveModExpr :: Replace (ModItem ReduceAnn)
halveModExpr (ModCA ca) = ModCA <$> combine contAssignExpr halveIndExpr ca
-halveModExpr a = Single a
-
--- | Remove all the undefined mod instances.
-cleanModInst :: (SourceInfo ann) -> (SourceInfo ann)
-cleanModInst srcInfo = srcInfo & infoSrc . _Wrapped .~ cleaned
- where
- validInst = srcInfo ^.. infoSrc . _Wrapped . traverse . modId
- cleaned = cleanModInst' validInst <$> srcInfo ^. infoSrc . _Wrapped
-
--- | Clean all the undefined module instances in a specific module using a
--- context.
-cleanModInst' :: [Identifier] -> (ModDecl ann) -> (ModDecl ann)
-cleanModInst' ids m = m & modItems .~ newModItem
- where newModItem = filter (validModInst ids) $ m ^.. modItems . traverse
-
--- | Check if a mod instance is in the current context.
-validModInst :: [Identifier] -> (ModItem ann) -> Bool
-validModInst ids (ModInst i _ _) = i `elem` ids
-validModInst _ _ = True
-
--- | Adds a '(ModDecl ann)' to a '(SourceInfo ann)'.
-addMod :: (ModDecl ann) -> (SourceInfo ann) -> (SourceInfo ann)
-addMod m srcInfo = srcInfo & infoSrc . _Wrapped %~ (m :)
+halveModExpr a = Single a
-- | Split a module declaration in half by trying to remove assign
-- statements. This is only done in the main module of the source.
-halveAssigns :: Replace (SourceInfo ann)
+halveAssigns :: Replace (SourceInfo ReduceAnn)
halveAssigns = combineL mainModule halveModAssign
-- | Checks if a module item is needed in the module declaration.
-relevantModItem :: (ModDecl ann) -> (ModItem ann) -> Bool
+relevantModItem :: (ModDecl ReduceAnn) -> (ModItem ReduceAnn) -> Bool
relevantModItem (ModDecl _ out _ _ _) (ModCA (ContAssign i _)) =
- i `elem` fmap _portName out
-relevantModItem _ Decl{} = True
-relevantModItem _ _ = False
+ i `elem` fmap _portName out
+relevantModItem _ Decl {} = True
+relevantModItem _ _ = False
-isAssign :: (Statement ann) -> Bool
-isAssign (BlockAssign _) = True
+isAssign :: (Statement ReduceAnn) -> Bool
+isAssign (BlockAssign _) = True
isAssign (NonBlockAssign _) = True
-isAssign _ = False
+isAssign (ForLoop _ _ _ _) = True
+isAssign _ = False
lValName :: LVal -> [Identifier]
-lValName (RegId i ) = [i]
+lValName (RegId i) = [i]
lValName (RegExpr i _) = [i]
lValName (RegSize i _) = [i]
lValName (RegConcat e) = mapMaybe getId . concat $ universe <$> e
where
getId (Id i) = Just i
- getId _ = Nothing
+ getId _ = Nothing
-- | Pretending that expr is an LVal for the case that it is in a module
-- instantiation.
exprName :: Expr -> [Identifier]
-exprName (Id i ) = [i]
-exprName (VecSelect i _) = [i]
+exprName (Id i) = [i]
+exprName (VecSelect i _) = [i]
exprName (RangeSelect i _) = [i]
-exprName (Concat i ) = concat . NonEmpty.toList $ exprName <$> i
-exprName _ = []
+exprName (Concat i) = concat . NonEmpty.toList $ exprName <$> i
+exprName _ = []
-- | Returns the only identifiers that are directly tied to an expression. This
-- is useful if one does not have to recurse deeper into the expressions.
exprId :: Expr -> Maybe Identifier
-exprId (Id i ) = Just i
-exprId (VecSelect i _) = Just i
+exprId (Id i) = Just i
+exprId (VecSelect i _) = Just i
exprId (RangeSelect i _) = Just i
-exprId _ = Nothing
+exprId _ = Nothing
eventId :: Event -> Maybe Identifier
-eventId (EId i) = Just i
+eventId (EId i) = Just i
eventId (EPosEdge i) = Just i
eventId (ENegEdge i) = Just i
-eventId _ = Nothing
+eventId _ = Nothing
portToId :: Port -> Identifier
portToId (Port _ _ _ i) = i
@@ -295,73 +290,91 @@ portToId (Port _ _ _ i) = i
paramToId :: Parameter -> Identifier
paramToId (Parameter i _) = i
-isModule :: Identifier -> (ModDecl ann) -> Bool
+isModule :: Identifier -> (ModDecl ReduceAnn) -> Bool
isModule i (ModDecl n _ _ _ _) = i == n
-modInstActive :: [(ModDecl ann)] -> (ModItem ann) -> [Identifier]
+modInstActive :: [(ModDecl ReduceAnn)] -> (ModItem ReduceAnn) -> [Identifier]
modInstActive decl (ModInst n _ i) = case m of
- Nothing -> []
- Just m' -> concat $ calcActive m' <$> zip i [0 ..]
+ Nothing -> []
+ Just m' -> concat $ calcActive m' <$> zip i [0 ..]
where
m = safe head $ filter (isModule n) decl
- calcActive (ModDecl _ o _ _ _) (ModConn e, n') | n' < length o = exprName e
- | otherwise = []
+ calcActive (ModDecl _ o _ _ _) (ModConn e, n')
+ | n' < length o = exprName e
+ | otherwise = []
calcActive (ModDecl _ o _ _ _) (ModConnNamed i' e, _)
- | i' `elem` fmap _portName o = exprName e
- | otherwise = []
+ | i' `elem` fmap _portName o = exprName e
+ | otherwise = []
modInstActive _ _ = []
-fixModInst :: (SourceInfo ann) -> (ModItem ann) -> (ModItem ann)
+fixModInst :: (SourceInfo ReduceAnn) -> (ModItem ReduceAnn) -> (ModItem ReduceAnn)
fixModInst (SourceInfo _ (Verilog decl)) (ModInst n g i) = case m of
- Nothing -> error "Moditem not found"
- Just m' -> ModInst n g . mapMaybe (fixModInst' m') $ zip i [0 ..]
+ Nothing -> error "Moditem not found"
+ Just m' -> ModInst n g . mapMaybe (fixModInst' m') $ zip i [0 ..]
where
m = safe head $ filter (isModule n) decl
fixModInst' (ModDecl _ o i' _ _) (ModConn e, n')
- | n' < length o + length i' = Just $ ModConn e
- | otherwise = Nothing
+ | n' < length o + length i' = Just $ ModConn e
+ | otherwise = Nothing
fixModInst' (ModDecl _ o i'' _ _) (ModConnNamed i' e, _)
- | i' `elem` fmap _portName (o <> i'') = Just $ ModConnNamed i' e
- | otherwise = Nothing
+ | i' `elem` fmap _portName (o <> i'') = Just $ ModConnNamed i' e
+ | otherwise = Nothing
fixModInst _ a = a
-findActiveWires :: Identifier -> (SourceInfo ann) -> [Identifier]
+eventIdent :: Event -> [Identifier]
+eventIdent (EId i) = [i]
+eventIdent (EExpr e) =
+ case exprId e of
+ Nothing -> []
+ Just eid -> [eid]
+eventIdent EAll = []
+eventIdent (EPosEdge i) = [i]
+eventIdent (ENegEdge i) = [i]
+eventIdent (EOr e1 e2) = eventIdent e1 <> eventIdent e2
+eventIdent (EComb e1 e2) = eventIdent e1 <> eventIdent e2
+
+findActiveWires :: Identifier -> (SourceInfo ReduceAnn) -> [Identifier]
findActiveWires t src =
- nub
- $ assignWires
- <> assignStat
- <> fmap portToId i
- <> fmap portToId o
- <> fmap paramToId p
- <> modinstwires
+ nub $
+ assignWires
+ <> assignStat
+ <> fmap portToId i
+ <> fmap portToId o
+ <> fmap paramToId p
+ <> modinstwires
+ <> events
where
assignWires = m ^.. modItems . traverse . modContAssign . contAssignNetLVal
assignStat =
- concatMap lValName
- $ (allStat ^.. traverse . stmntBA . assignReg)
- <> (allStat ^.. traverse . stmntNBA . assignReg)
+ concatMap lValName $
+ (allStat ^.. traverse . stmntBA . assignReg)
+ <> (allStat ^.. traverse . stmntNBA . assignReg)
+ <> (allStat ^.. traverse . forAssign . assignReg)
+ <> (allStat ^.. traverse . forIncr . assignReg)
+ events = concatMap eventIdent $ (allStat ^.. traverse . statEvent)
allStat = filter isAssign . concat $ fmap universe stat
stat =
- (m ^.. modItems . traverse . _Initial)
- <> (m ^.. modItems . traverse . _Always)
+ (m ^.. modItems . traverse . _Initial)
+ <> (m ^.. modItems . traverse . _Always)
modinstwires =
- concat $ modInstActive (src ^. infoSrc . _Wrapped) <$> m ^. modItems
+ concat $ modInstActive (src ^. infoSrc . _Wrapped) <$> m ^. modItems
m@(ModDecl _ o i _ p) = src ^. aModule t
-- | Clean a specific module. Have to be carful that the module is in the
--- '(SourceInfo ann)', otherwise it will crash.
-cleanSourceInfo :: Identifier -> (SourceInfo ann) -> (SourceInfo ann)
+-- '(SourceInfo ReduceAnn)', otherwise it will crash.
+cleanSourceInfo :: Identifier -> (SourceInfo ReduceAnn) -> (SourceInfo ReduceAnn)
cleanSourceInfo t src = src & aModule t %~ clean (findActiveWires t src)
-cleanSourceInfoAll :: (SourceInfo ann) -> (SourceInfo ann)
+cleanSourceInfoAll :: (SourceInfo ReduceAnn) -> (SourceInfo ReduceAnn)
cleanSourceInfoAll src = foldr cleanSourceInfo src allMods
- where allMods = src ^.. infoSrc . _Wrapped . traverse . modId
+ where
+ allMods = src ^.. infoSrc . _Wrapped . traverse . modId
-- | Returns true if the text matches the name of a module.
-matchesModName :: Identifier -> (ModDecl ann) -> Bool
+matchesModName :: Identifier -> (ModDecl ReduceAnn) -> Bool
matchesModName top (ModDecl i _ _ _ _) = top == i
-halveStatement :: Replace (Statement ann)
+halveStatement :: Replace (Statement ReduceAnn)
halveStatement (SeqBlock [s]) = halveStatement s
halveStatement (SeqBlock s) = SeqBlock <$> halve s
halveStatement (CondStmnt _ (Just s1) (Just s2)) = Dual s1 s2
@@ -371,55 +384,80 @@ halveStatement (EventCtrl e (Just s)) = EventCtrl e . Just <$> halveStatement s
halveStatement (TimeCtrl e (Just s)) = TimeCtrl e . Just <$> halveStatement s
halveStatement a = Single a
-halveAlways :: Replace (ModItem ann)
-halveAlways (Always s) = Always <$> halveStatement s
-halveAlways a = Single a
+halveAlways :: Replace (ModItem ReduceAnn)
+halveAlways (ModItemAnn Active (Always s)) = ModItemAnn Active . Always <$> halveStatement s
+halveAlways r@(ModItemAnn Reduced (Always s)) = Single r
+halveAlways a = Single a
+
+-- | Check if a mod instance is in the current context.
+validModInst :: [Identifier] -> (ModItem ReduceAnn) -> Bool
+validModInst ids (ModInst i _ _) = i `elem` ids
+validModInst _ _ = True
+
+-- | Clean all the undefined module instances in a specific module using a
+-- context.
+cleanModInst' :: [Identifier] -> (ModDecl ReduceAnn) -> (ModDecl ReduceAnn)
+cleanModInst' ids m = m & modItems .~ newModItem
+ where
+ newModItem = filter (validModInst ids) $ m ^.. modItems . traverse
+
+-- | Remove all the undefined mod instances.
+cleanModInst :: (SourceInfo ReduceAnn) -> (SourceInfo ReduceAnn)
+cleanModInst srcInfo = srcInfo & infoSrc . _Wrapped .~ cleaned
+ where
+ validInst = srcInfo ^.. infoSrc . _Wrapped . traverse . modId
+ cleaned = cleanModInst' validInst <$> srcInfo ^. infoSrc . _Wrapped
+
+-- | Adds a '(ModDecl ReduceAnn)' to a '(SourceInfo ReduceAnn)'.
+addMod :: (ModDecl ReduceAnn) -> (SourceInfo ReduceAnn) -> (SourceInfo ReduceAnn)
+addMod m srcInfo = srcInfo & infoSrc . _Wrapped %~ (m :)
-- | Removes half the modules randomly, until it reaches a minimal amount of
-- modules. This is done by doing a binary search on the list of modules and
-- removing the instantiations from the main module body.
-halveModules :: Replace (SourceInfo ann)
+halveModules :: Replace (SourceInfo ReduceAnn)
halveModules srcInfo@(SourceInfo top _) =
- cleanSourceInfoAll
- . cleanModInst
- . addMod main
- <$> combine (infoSrc . _Wrapped) repl srcInfo
+ cleanSourceInfoAll
+ . cleanModInst
+ . addMod main
+ <$> combine (infoSrc . _Wrapped) repl srcInfo
where
repl = halve . filter (not . matchesModName (Identifier top))
main = srcInfo ^. mainModule
-moduleBot :: (SourceInfo ann) -> Bool
-moduleBot (SourceInfo _ (Verilog [] )) = True
+moduleBot :: (SourceInfo ReduceAnn) -> Bool
+moduleBot (SourceInfo _ (Verilog [])) = True
moduleBot (SourceInfo _ (Verilog [_])) = True
-moduleBot (SourceInfo _ (Verilog _ )) = False
+moduleBot (SourceInfo _ (Verilog _)) = False
-- | Reducer for module items. It does a binary search on all the module items,
-- except assignments to outputs and input-output declarations.
-halveModItems :: Identifier -> Replace (SourceInfo ann)
+halveModItems :: Identifier -> Replace (SourceInfo ReduceAnn)
halveModItems t srcInfo = cleanSourceInfo t . addRelevant <$> src
where
- repl = halve . filter (not . relevantModItem main)
- relevant = filter (relevantModItem main) $ main ^. modItems
- main = srcInfo ^. aModule t
- src = combine (aModule t . modItems) repl srcInfo
+ repl = halve . filter (not . relevantModItem main)
+ relevant = filter (relevantModItem main) $ main ^. modItems
+ main = srcInfo ^. aModule t
+ src = combine (aModule t . modItems) repl srcInfo
addRelevant = aModule t . modItems %~ (relevant ++)
-modItemBot :: Identifier -> (SourceInfo ann) -> Bool
-modItemBot t srcInfo | length modItemsNoDecl > 2 = False
- | otherwise = True
+modItemBot :: Identifier -> (SourceInfo ReduceAnn) -> Bool
+modItemBot t srcInfo
+ | length modItemsNoDecl > 2 = False
+ | otherwise = True
where
modItemsNoDecl =
- filter noDecl $ srcInfo ^.. aModule t . modItems . traverse
- noDecl Decl{} = False
- noDecl _ = True
+ filter noDecl $ srcInfo ^.. aModule t . modItems . traverse
+ noDecl Decl {} = False
+ noDecl _ = True
-halveStatements :: Identifier -> Replace (SourceInfo ann)
+halveStatements :: Identifier -> Replace (SourceInfo ReduceAnn)
halveStatements t m =
- cleanSourceInfo t <$> combine (aModule t . modItems) (traverse halveAlways) m
+ cleanSourceInfo t <$> combine (aModule t . modItems) (traverse halveAlways) m
-- | Reduce expressions by splitting them in half and keeping the half that
-- succeeds.
-halveExpr :: Identifier -> Replace (SourceInfo ann)
+halveExpr :: Identifier -> Replace (SourceInfo ReduceAnn)
halveExpr t = combine (aModule t . modItems) $ traverse halveModExpr
toIds :: [Expr] -> [Identifier]
@@ -431,66 +469,66 @@ toIdsConst = toIds . fmap constToExpr
toIdsEvent :: [Event] -> [Identifier]
toIdsEvent = nub . mapMaybe eventId . concatMap universe
-allStatIds' :: (Statement ann) -> [Identifier]
+allStatIds' :: (Statement ReduceAnn) -> [Identifier]
allStatIds' s = nub $ assignIds <> otherExpr <> eventProcessedIds
where
assignIds =
- toIds
- $ (s ^.. stmntBA . assignExpr)
- <> (s ^.. stmntNBA . assignExpr)
- <> (s ^.. forAssign . assignExpr)
- <> (s ^.. forIncr . assignExpr)
- otherExpr = toIds $ (s ^.. forExpr) <> (s ^.. stmntCondExpr)
+ toIds $
+ (s ^.. stmntBA . assignExpr)
+ <> (s ^.. stmntNBA . assignExpr)
+ <> (s ^.. forAssign . assignExpr)
+ <> (s ^.. forIncr . assignExpr)
+ otherExpr = toIds $ (s ^.. forExpr) <> (s ^.. stmntCondExpr)
eventProcessedIds = toIdsEvent $ s ^.. statEvent
-allStatIds :: (Statement ann) -> [Identifier]
+allStatIds :: (Statement ReduceAnn) -> [Identifier]
allStatIds s = nub . concat $ allStatIds' <$> universe s
fromRange :: Range -> [ConstExpr]
fromRange r = [rangeMSB r, rangeLSB r]
-allExprIds :: (ModDecl ann) -> [Identifier]
+allExprIds :: (ModDecl ReduceAnn) -> [Identifier]
allExprIds m =
- nub
- $ contAssignIds
- <> modInstIds
- <> modInitialIds
- <> modAlwaysIds
- <> modPortIds
- <> modDeclIds
- <> paramIds
+ nub $
+ contAssignIds
+ <> modInstIds
+ <> modInitialIds
+ <> modAlwaysIds
+ <> modPortIds
+ <> modDeclIds
+ <> paramIds
where
contAssignIds =
- toIds $ m ^.. modItems . traverse . modContAssign . contAssignExpr
+ toIds $ m ^.. modItems . traverse . modContAssign . contAssignExpr
modInstIds =
- toIds $ m ^.. modItems . traverse . modInstConns . traverse . modExpr
+ toIds $ m ^.. modItems . traverse . modInstConns . traverse . modExpr
modInitialIds =
- nub . concatMap allStatIds $ m ^.. modItems . traverse . _Initial
+ nub . concatMap allStatIds $ m ^.. modItems . traverse . _Initial
modAlwaysIds =
- nub . concatMap allStatIds $ m ^.. modItems . traverse . _Always
+ nub . concatMap allStatIds $ m ^.. modItems . traverse . _Always
modPortIds =
- nub
- . concatMap (toIdsConst . fromRange)
- $ m
- ^.. modItems
- . traverse
- . declPort
- . portSize
+ nub
+ . concatMap (toIdsConst . fromRange)
+ $ m
+ ^.. modItems
+ . traverse
+ . declPort
+ . portSize
modDeclIds = toIdsConst $ m ^.. modItems . traverse . declVal . _Just
paramIds =
- toIdsConst
- $ (m ^.. modItems . traverse . paramDecl . traverse . paramValue)
- <> ( m
- ^.. modItems
- . traverse
- . localParamDecl
- . traverse
- . localParamValue
- )
-
-isUsedDecl :: [Identifier] -> (ModItem ann) -> Bool
+ toIdsConst $
+ (m ^.. modItems . traverse . paramDecl . traverse . paramValue)
+ <> ( m
+ ^.. modItems
+ . traverse
+ . localParamDecl
+ . traverse
+ . localParamValue
+ )
+
+isUsedDecl :: [Identifier] -> (ModItem ReduceAnn) -> Bool
isUsedDecl ids (Decl _ (Port _ _ _ i) _) = i `elem` ids
-isUsedDecl _ _ = True
+isUsedDecl _ _ = True
isUsedParam :: [Identifier] -> Parameter -> Bool
isUsedParam ids (Parameter i _) = i `elem` ids
@@ -498,162 +536,231 @@ isUsedParam ids (Parameter i _) = i `elem` ids
isUsedPort :: [Identifier] -> Port -> Bool
isUsedPort ids (Port _ _ _ i) = i `elem` ids
-removeDecl :: (SourceInfo ann) -> (SourceInfo ann)
+-- | Should return true if there is any active tag present.
+checkActiveTag :: ModDecl ReduceAnn -> Bool
+checkActiveTag m = (/= []) . filter hasActiveTag $ _modItems m
+ where
+ hasActiveTag (ModItemAnn Active (Always _)) = True
+ hasActiveTag _ = False
+
+tagAlwaysBlockMis :: [ModItem ReduceAnn] -> [ModItem ReduceAnn]
+tagAlwaysBlockMis [] = []
+tagAlwaysBlockMis (mi@(Always _) : mis) = ModItemAnn Active mi : mis
+tagAlwaysBlockMis (mi : mis) = mi : tagAlwaysBlockMis mis
+
+-- | Tag an always block to be reduced if there are no active ones.
+tagAlwaysBlock :: ModDecl ReduceAnn -> ModDecl ReduceAnn
+tagAlwaysBlock m
+ | checkActiveTag m = m
+ | otherwise = m {_modItems = tagAlwaysBlockMis (_modItems m)}
+
+tagAlwaysBlockReducedMis :: [ModItem ReduceAnn] -> [ModItem ReduceAnn]
+tagAlwaysBlockReducedMis [] = []
+tagAlwaysBlockReducedMis ((ModItemAnn Active mi) : mis) =
+ ModItemAnn Reduced mi : tagAlwaysBlockReducedMis mis
+tagAlwaysBlockReducedMis (mi : mis) = mi : tagAlwaysBlockReducedMis mis
+
+-- | Tag an always block to be reduced if there are no active ones.
+tagAlwaysBlockReduced :: ModDecl ReduceAnn -> ModDecl ReduceAnn
+tagAlwaysBlockReduced m = m {_modItems = tagAlwaysBlockReducedMis (_modItems m)}
+
+tAlways ::
+ (ModDecl ReduceAnn -> ModDecl ReduceAnn) ->
+ Identifier ->
+ SourceInfo ReduceAnn ->
+ SourceInfo ReduceAnn
+tAlways f t m =
+ m & aModule t %~ f
+
+tagAlways, untagAlways, idTag :: Identifier -> SourceInfo ReduceAnn -> SourceInfo ReduceAnn
+tagAlways = tAlways tagAlwaysBlock
+untagAlways = tAlways tagAlwaysBlockReduced
+idTag = const id
+
+removeDecl :: SourceInfo ReduceAnn -> SourceInfo ReduceAnn
removeDecl src = foldr fix removed allMods
where
removeDecl' t src' =
- src'
- & (\a -> a & aModule t . modItems %~ filter
+ src'
+ & ( \a ->
+ a & aModule t . modItems
+ %~ filter
(isUsedDecl (used <> findActiveWires t a))
- )
- . (aModule t . modParams %~ filter (isUsedParam used))
- . (aModule t . modInPorts %~ filter (isUsedPort used))
- where used = nub $ allExprIds (src' ^. aModule t)
+ )
+ . (aModule t . modParams %~ filter (isUsedParam used))
+ . (aModule t . modInPorts %~ filter (isUsedPort used))
+ where
+ used = nub $ allExprIds (src' ^. aModule t)
allMods = src ^.. infoSrc . _Wrapped . traverse . modId
fix t a = a & aModule t . modItems %~ fmap (fixModInst a)
removed = foldr removeDecl' src allMods
-defaultBot :: (SourceInfo ann) -> Bool
+defaultBot :: (SourceInfo ReduceAnn) -> Bool
defaultBot = const False
-- | Reduction using custom reduction strategies.
-reduce_
- :: (MonadSh m, Eq ann)
- => Shelly.FilePath
- -> Text
- -> Replace (SourceInfo ann)
- -> ((SourceInfo ann) -> Bool)
- -> ((SourceInfo ann) -> m Bool)
- -> (SourceInfo ann)
- -> m (SourceInfo ann)
-reduce_ out title repl bot eval src = do
- writefile out $ genSource src
- liftSh
- . Shelly.echo
- $ "Reducing "
- <> title
- <> " (Modules: "
- <> showT (length . getVerilog $ _infoSrc src)
- <> ", Module items: "
- <> showT
- (length
- (src ^.. infoSrc . _Wrapped . traverse . modItems . traverse)
- )
- <> ")"
- if bot src
- then return src
- else case repl src of
- Single s -> do
- red <- eval s
- if red
- then if cond s then recReduction s else return s
- else return src
- Dual l r -> do
- red <- eval l
- if red
- then if cond l then recReduction l else return l
- else do
- red' <- eval r
- if red'
- then if cond r then recReduction r else return r
- else return src
- None -> return src
+reduce_ ::
+ (MonadSh m) =>
+ Shelly.FilePath ->
+ (SourceInfo ReduceAnn -> m Bool) ->
+ Text ->
+ (SourceInfo ReduceAnn -> SourceInfo ReduceAnn) ->
+ (SourceInfo ReduceAnn -> SourceInfo ReduceAnn) ->
+ Replace (SourceInfo ReduceAnn) ->
+ (SourceInfo ReduceAnn -> Bool) ->
+ SourceInfo ReduceAnn ->
+ m (SourceInfo ReduceAnn)
+reduce_ out eval title tag untag repl bot usrc = do
+ writefile out $ genSource src
+ liftSh
+ . Shelly.echo
+ $ "Reducing " <> title <> " (modules: "
+ <> showT (length . getVerilog $ _infoSrc src)
+ <> ", module items: "
+ <> showT (length (src ^.. infoSrc . _Wrapped . traverse . modItems . traverse))
+ <> ", loc: "
+ <> showT (length . lines . unpack $ genSource usrc)
+ <> ")"
+ if bot src
+ then return $ untag src
+ else case repl src of
+ Single s -> do
+ red <- eval s
+ if red
+ then if s /= src then recReduction s else return $ untag src
+ else return $ untag src
+ Dual l r -> do
+ red <- eval l
+ if red
+ then if l /= src then recReduction l else return $ untag src
+ else do
+ red' <- eval r
+ if red'
+ then if r /= src then recReduction r else return $ untag src
+ else return $ untag src
+ None -> return $ untag src
where
- cond s = s /= src
- recReduction = reduce_ out title repl bot eval
+ src = tag usrc
+ recReduction = reduce_ out eval title tag untag repl bot
-- | Reduce an input to a minimal representation. It follows the reduction
-- strategy mentioned above.
-reduce
- :: (MonadSh m, Eq ann)
- => Shelly.FilePath -- ^ Filepath for temporary file.
- -> ((SourceInfo ann) -> m Bool) -- ^ Failed or not.
- -> (SourceInfo ann) -- ^ Input verilog source to be reduced.
- -> m (SourceInfo ann) -- ^ Reduced output.
-reduce fp eval src =
- fmap removeDecl
- $ red "Modules" moduleBot halveModules src
- >>= redAll "Module items" modItemBot halveModItems
- >>= redAll "Statements" (const defaultBot) halveStatements
- -- >>= redAll "Expressions" (const defaultBot) halveExpr
- >>= red "Remove constants in concat" defaultBot removeConstInConcat
- >>= red "Cleaning" defaultBot (pure . removeDecl)
+reduce ::
+ (MonadSh m) =>
+ -- | Filepath for temporary file.
+ Shelly.FilePath ->
+ -- | Failed or not.
+ (SourceInfo ReduceAnn -> m Bool) ->
+ -- | Input verilog source to be reduced.
+ SourceInfo () ->
+ -- | Reduced output.
+ m (SourceInfo ())
+reduce fp eval rsrc =
+ fmap (clearAnn . removeDecl) $
+ red "Modules" id id halveModules moduleBot src
+ >>= redAll "Module items" idTag idTag halveModItems modItemBot
+ >>= redAll "Statements" tagAlways untagAlways halveStatements (const defaultBot)
+ -- >>= redAll "Expressions" halveExpr (const defaultBot)
+ >>= red "Remove constants in concat" id id removeConstInConcat defaultBot
+ >>= red "Cleaning" id id (pure . removeDecl) defaultBot
where
- red s bot a = reduce_ fp s a bot eval
- red' s bot a t = reduce_ fp s (a t) (bot t) eval
- redAll s bot halve' src' = foldrM
- (\t -> red' (s <> " (" <> getIdentifier t <> ")") bot halve' t)
+ red = reduce_ fp eval
+ redAll s tag untag halve' bot src' =
+ foldrM
+ (\t -> red (s <> " (" <> getIdentifier t <> ")") (tag t) (untag t) (halve' t) (bot t))
src'
(src' ^.. infoSrc . _Wrapped . traverse . modId)
-
-runScript
- :: (MonadSh m, Eq ann) => Shelly.FilePath -> Shelly.FilePath -> (SourceInfo ann) -> m Bool
+ src = fmap (\_ -> Idle) rsrc
+
+runScript ::
+ (MonadSh m, Show ann) =>
+ Shelly.FilePath ->
+ Shelly.FilePath ->
+ (SourceInfo ann) ->
+ m Bool
runScript fp file src = do
- e <- liftSh $ do
- Shelly.writefile file $ genSource src
- noPrint . Shelly.errExit False $ Shelly.run_ fp []
- Shelly.lastExitCode
- return $ e == 0
+ e <- liftSh $ do
+ Shelly.writefile file $ genSource src
+ noPrint . Shelly.errExit False $ Shelly.run_ fp []
+ Shelly.lastExitCode
+ return $ e == 0
-- | Reduce using a script that is passed to it
-reduceWithScript
- :: (MonadSh m, MonadIO m)
- => Text
- -> Shelly.FilePath
- -> Shelly.FilePath
- -> m ()
+reduceWithScript ::
+ (MonadSh m, MonadIO m) =>
+ Text ->
+ Shelly.FilePath ->
+ Shelly.FilePath ->
+ m ()
reduceWithScript top script file = do
- liftSh . Shelly.cp file $ file <.> "original"
- (srcInfo :: SourceInfo ()) <- liftIO . parseSourceInfoFile top $ Shelly.toTextIgnore file
- void $ reduce (fromText "reduce_script.v") (runScript script file) srcInfo
-
--- | Reduce a '(SourceInfo ann)' using two 'Synthesiser' that are passed to it.
-reduceSynth
- :: (Synthesiser a, Synthesiser b, MonadSh m, Eq ann)
- => Maybe Text
- -> Shelly.FilePath
- -> a
- -> b
- -> (SourceInfo ann)
- -> m (SourceInfo ann)
-reduceSynth mt datadir a b = reduce (fromText $ "reduce_" <> toText a <> "_" <> toText b <> ".v") synth
+ liftSh . Shelly.cp file $ file <.> "original"
+ (srcInfo :: SourceInfo ()) <- liftIO . parseSourceInfoFile top $ Shelly.toTextIgnore file
+ void $ reduce (fromText "reduce_script.v") (runScript script file) srcInfo
+
+-- | Reduce a '(SourceInfo ReduceAnn)' using two 'Synthesiser' that are passed to it.
+reduceSynth ::
+ (Synthesiser a, Synthesiser b, MonadSh m) =>
+ Maybe Text ->
+ Shelly.FilePath ->
+ a ->
+ b ->
+ SourceInfo () ->
+ m (SourceInfo ())
+reduceSynth mt datadir a b src = do
+ counter <- liftSh . liftIO $ newIORef (0 :: Int)
+ reduce (fromText $ prefix <> ".v") (synth counter) src
where
- synth src' = liftSh $ do
- r <- runResultT $ do
- runSynth a src'
- runSynth b src'
- runEquiv mt datadir a b src'
- return $ case r of
- Fail (EquivFail _) -> True
- _ -> False
-
-reduceSynthesis :: (Synthesiser a, MonadSh m, Eq ann) => a -> (SourceInfo ann) -> m (SourceInfo ann)
+ synth counter src' = liftSh $ do
+ count <- liftIO $ readIORef counter
+ liftIO $ writeIORef counter (count + 1)
+ Shelly.mkdir (fromText $ prefix <> "_" <> showT count)
+ current_dir <- Shelly.pwd
+ Shelly.cd (fromText $ prefix <> "_" <> showT count)
+ r <- runResultT $ do
+ runSynth a src'
+ runSynth b src'
+ runEquiv mt datadir a b src'
+ Shelly.cd current_dir
+ return $ case r of
+ Fail (EquivFail _) -> True
+ _ -> False
+ prefix = "reduce_" <> toText a <> "_" <> toText b
+
+reduceSynthesis :: (Synthesiser a, MonadSh m) => a -> SourceInfo () -> m (SourceInfo ())
reduceSynthesis a = reduce (fromText $ "reduce_" <> toText a <> ".v") synth
where
synth src = liftSh $ do
- r <- runResultT $ runSynth a src
- return $ case r of
- Fail SynthFail -> True
- _ -> False
+ r <- runResultT $ runSynth a src
+ return $ case r of
+ Fail SynthFail -> True
+ _ -> False
runInTmp :: Shelly.Sh a -> Shelly.Sh a
-runInTmp a = Shelly.withTmpDir $ (\f -> do
- dir <- Shelly.pwd
- Shelly.cd f
- r <- a
- Shelly.cd dir
- return r)
-
-reduceSimIc :: (Synthesiser a, MonadSh m, Eq ann) => Shelly.FilePath -> [ByteString]
- -> a -> (SourceInfo ann) -> m (SourceInfo ann)
+runInTmp a =
+ Shelly.withTmpDir $
+ ( \f -> do
+ dir <- Shelly.pwd
+ Shelly.cd f
+ r <- a
+ Shelly.cd dir
+ return r
+ )
+
+reduceSimIc ::
+ (Synthesiser a, MonadSh m) =>
+ Shelly.FilePath ->
+ [ByteString] ->
+ a ->
+ SourceInfo () ->
+ m (SourceInfo ())
reduceSimIc fp bs a = reduce (fromText $ "reduce_sim_" <> toText a <> ".v") synth
where
synth src = liftSh . runInTmp $ do
- r <- runResultT $ do
- runSynth a src
- runSynth defaultIdentity src
- i <- runSimIc fp defaultIcarus defaultIdentity src bs Nothing
- runSimIc fp defaultIcarus a src bs $ Just i
- return $ case r of
- Fail (SimFail _) -> True
- _ -> False
+ r <- runResultT $ do
+ runSynth a src
+ runSynth defaultIdentity src
+ i <- runSimIc fp defaultIcarus defaultIdentity src bs Nothing
+ runSimIc fp defaultIcarus a src bs $ Just i
+ return $ case r of
+ Fail (SimFail _) -> True
+ _ -> False