2019-03-06 06:51:09 +01:00
|
|
|
{- sv2v
|
|
|
|
|
- Author: Zachary Snow <zach@zachjs.com>
|
|
|
|
|
-
|
2019-08-09 05:12:49 +02:00
|
|
|
- Conversion for `struct packed` and `union packed`
|
2019-03-06 06:51:09 +01:00
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
module Convert.Struct (convert) where
|
|
|
|
|
|
2019-04-22 08:48:22 +02:00
|
|
|
import Control.Monad.State
|
|
|
|
|
import Control.Monad.Writer
|
2019-10-14 01:01:42 +02:00
|
|
|
import Data.List (partition)
|
2019-03-06 06:51:09 +01:00
|
|
|
import Data.Tuple (swap)
|
|
|
|
|
import qualified Data.Map.Strict as Map
|
2019-04-22 04:22:33 +02:00
|
|
|
import qualified Data.Set as Set
|
2019-03-06 06:51:09 +01:00
|
|
|
|
|
|
|
|
import Convert.Traverse
|
|
|
|
|
import Language.SystemVerilog.AST
|
|
|
|
|
|
|
|
|
|
type TypeFunc = [Range] -> Type
|
|
|
|
|
type StructInfo = (Type, Map.Map Identifier (Range, Expr))
|
|
|
|
|
type Structs = Map.Map TypeFunc StructInfo
|
|
|
|
|
type Types = Map.Map Identifier Type
|
2019-04-22 04:22:33 +02:00
|
|
|
type Idents = Set.Set Identifier
|
2019-03-06 06:51:09 +01:00
|
|
|
|
2019-04-24 00:44:45 +02:00
|
|
|
convert :: [AST] -> [AST]
|
|
|
|
|
convert = map $ traverseDescriptions convertDescription
|
2019-03-06 06:51:09 +01:00
|
|
|
|
|
|
|
|
convertDescription :: Description -> Description
|
2019-09-16 05:17:14 +02:00
|
|
|
convertDescription (description @ Part{}) =
|
2019-04-22 08:33:24 +02:00
|
|
|
traverseModuleItems (traverseTypes $ convertType structs) $
|
2019-09-16 05:17:14 +02:00
|
|
|
Part attrs extern kw lifetime name ports (items ++ funcs)
|
2019-03-06 06:51:09 +01:00
|
|
|
where
|
2019-09-16 05:17:14 +02:00
|
|
|
description' @ (Part attrs extern kw lifetime name ports items) =
|
2019-08-07 05:11:06 +02:00
|
|
|
scopedConversion (traverseDeclM structs) traverseModuleItemM
|
|
|
|
|
traverseStmtM tfArgTypes description
|
2019-04-22 04:22:33 +02:00
|
|
|
-- collect information about this description
|
2019-03-06 06:51:09 +01:00
|
|
|
structs = execWriter $ collectModuleItemsM
|
2019-04-22 08:48:22 +02:00
|
|
|
(collectTypesM collectStructM) description
|
2019-04-22 19:58:14 +02:00
|
|
|
tfArgTypes = execWriter $ collectModuleItemsM collectTFArgsM description
|
2019-04-22 04:22:33 +02:00
|
|
|
-- determine which of the packer functions we actually need
|
|
|
|
|
calledFuncs = execWriter $ collectModuleItemsM
|
2019-04-22 08:48:22 +02:00
|
|
|
(collectExprsM $ collectNestedExprsM collectCallsM) description'
|
2019-04-22 04:22:33 +02:00
|
|
|
packerFuncs = Set.map packerFnName $ Map.keysSet structs
|
|
|
|
|
calledPackedFuncs = Set.intersection calledFuncs packerFuncs
|
2019-04-22 08:48:22 +02:00
|
|
|
funcs = map packerFn $ filter isNeeded $ Map.keys structs
|
2019-04-22 07:18:25 +02:00
|
|
|
isNeeded tf = Set.member (packerFnName tf) calledPackedFuncs
|
2019-04-22 08:33:24 +02:00
|
|
|
-- helpers for the scoped traversal
|
|
|
|
|
traverseModuleItemM :: ModuleItem -> State Types ModuleItem
|
|
|
|
|
traverseModuleItemM item =
|
2019-09-25 04:04:24 +02:00
|
|
|
traverseLHSsM traverseLHSM item >>=
|
|
|
|
|
traverseExprsM traverseExprM >>=
|
2019-04-22 08:33:24 +02:00
|
|
|
traverseAsgnsM traverseAsgnM
|
|
|
|
|
traverseStmtM :: Stmt -> State Types Stmt
|
2019-04-24 09:37:47 +02:00
|
|
|
traverseStmtM (Subroutine Nothing f args) = do
|
2019-04-22 19:58:14 +02:00
|
|
|
stateTypes <- get
|
2019-04-24 09:37:47 +02:00
|
|
|
return $ uncurry (Subroutine Nothing) $
|
|
|
|
|
convertCall structs stateTypes f args
|
2019-04-22 08:33:24 +02:00
|
|
|
traverseStmtM stmt =
|
2019-09-25 04:04:24 +02:00
|
|
|
traverseStmtLHSsM traverseLHSM stmt >>=
|
|
|
|
|
traverseStmtExprsM traverseExprM >>=
|
2019-04-22 08:33:24 +02:00
|
|
|
traverseStmtAsgnsM traverseAsgnM
|
2019-04-22 08:48:22 +02:00
|
|
|
traverseExprM =
|
|
|
|
|
traverseNestedExprsM $ stately converter
|
|
|
|
|
where
|
|
|
|
|
converter :: Types -> Expr -> Expr
|
|
|
|
|
converter types expr =
|
|
|
|
|
snd $ convertAsgn structs types (LHSIdent "", expr)
|
2019-09-25 04:04:24 +02:00
|
|
|
traverseLHSM =
|
|
|
|
|
traverseNestedLHSsM $ stately converter
|
|
|
|
|
where
|
|
|
|
|
converter :: Types -> LHS -> LHS
|
|
|
|
|
converter types lhs =
|
|
|
|
|
fst $ convertAsgn structs types (lhs, Ident "")
|
2019-04-22 08:33:24 +02:00
|
|
|
traverseAsgnM = stately $ convertAsgn structs
|
2019-04-22 07:18:25 +02:00
|
|
|
convertDescription other = other
|
2019-04-22 04:22:33 +02:00
|
|
|
|
2019-04-22 08:48:22 +02:00
|
|
|
-- write down unstructured versions of packed struct types
|
|
|
|
|
collectStructM :: Type -> Writer Structs ()
|
2019-10-15 04:01:52 +02:00
|
|
|
collectStructM (Struct Unpacked fields _) =
|
|
|
|
|
collectStructM' (Struct Unpacked) True Unspecified fields
|
2019-08-09 05:12:49 +02:00
|
|
|
collectStructM (Struct (Packed sg) fields _) =
|
2019-10-15 04:01:52 +02:00
|
|
|
collectStructM' (Struct $ Packed sg) True sg fields
|
2019-08-09 05:12:49 +02:00
|
|
|
collectStructM (Union (Packed sg) fields _) =
|
2019-10-15 04:01:52 +02:00
|
|
|
collectStructM' (Union $ Packed sg) False sg fields
|
2019-08-09 05:12:49 +02:00
|
|
|
collectStructM _ = return ()
|
|
|
|
|
|
|
|
|
|
collectStructM'
|
2019-09-25 04:04:24 +02:00
|
|
|
:: ([Field] -> [Range] -> Type)
|
2019-08-09 05:12:49 +02:00
|
|
|
-> Bool -> Signing -> [Field] -> Writer Structs ()
|
|
|
|
|
collectStructM' constructor isStruct sg fields = do
|
2019-03-06 06:51:09 +01:00
|
|
|
if canUnstructure
|
|
|
|
|
then tell $ Map.singleton
|
2019-09-25 04:04:24 +02:00
|
|
|
(constructor fields)
|
2019-03-06 06:51:09 +01:00
|
|
|
(unstructType, unstructFields)
|
|
|
|
|
else return ()
|
|
|
|
|
where
|
|
|
|
|
zero = Number "0"
|
|
|
|
|
typeRange :: Type -> Range
|
|
|
|
|
typeRange t =
|
|
|
|
|
if null ranges then (zero, zero) else head ranges
|
|
|
|
|
where ranges = snd $ typeRanges t
|
|
|
|
|
|
|
|
|
|
-- extract info about the fields
|
|
|
|
|
fieldTypes = map fst fields
|
|
|
|
|
fieldRanges = map typeRange fieldTypes
|
|
|
|
|
fieldSizes = map rangeSize fieldRanges
|
|
|
|
|
|
|
|
|
|
-- layout the fields into the unstructured type; note that `scanr` is
|
|
|
|
|
-- used here because SystemVerilog structs are laid out backwards
|
2019-08-09 05:12:49 +02:00
|
|
|
fieldLos =
|
|
|
|
|
if isStruct
|
|
|
|
|
then map simplify $ tail $ scanr (BinOp Add) (Number "0") fieldSizes
|
|
|
|
|
else map simplify $ repeat (Number "0")
|
|
|
|
|
fieldHis =
|
|
|
|
|
if isStruct
|
|
|
|
|
then map simplify $ init $ scanr (BinOp Add) (Number "-1") fieldSizes
|
|
|
|
|
else map simplify $ map (BinOp Add (Number "-1")) fieldSizes
|
2019-03-06 06:51:09 +01:00
|
|
|
|
|
|
|
|
-- create the mapping structure for the unstructured fields
|
|
|
|
|
unstructOffsets = map simplify $ map snd fieldRanges
|
|
|
|
|
unstructRanges = zip fieldHis fieldLos
|
|
|
|
|
keys = map snd fields
|
|
|
|
|
vals = zip unstructRanges unstructOffsets
|
|
|
|
|
unstructFields = Map.fromList $ zip keys vals
|
|
|
|
|
|
2019-05-10 16:41:31 +02:00
|
|
|
-- create the unstructured type; result type takes on the signing of the
|
|
|
|
|
-- struct itself to preserve behavior of operations on the whole struct
|
2019-08-09 05:12:49 +02:00
|
|
|
structSize =
|
|
|
|
|
if isStruct
|
|
|
|
|
then foldl1 (BinOp Add) fieldSizes
|
|
|
|
|
else head fieldSizes
|
2019-03-06 06:51:09 +01:00
|
|
|
packedRange = (simplify $ BinOp Sub structSize (Number "1"), zero)
|
2019-05-10 16:41:31 +02:00
|
|
|
unstructType = IntegerVector TLogic sg [packedRange]
|
2019-03-06 06:51:09 +01:00
|
|
|
|
2019-05-10 16:41:31 +02:00
|
|
|
-- check if this struct can be packed into an integer vector; integer
|
|
|
|
|
-- atoms and non-integers do not have a definitive size, and so cannot
|
|
|
|
|
-- be packed; net types are not permitted as struct fields
|
|
|
|
|
isIntVec :: Type -> Bool
|
|
|
|
|
isIntVec (IntegerVector _ _ _) = True
|
|
|
|
|
isIntVec _ = False
|
|
|
|
|
canUnstructure = all isIntVec fieldTypes
|
2019-03-06 06:51:09 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
-- convert a struct type to its unstructured equivalent
|
|
|
|
|
convertType :: Structs -> Type -> Type
|
|
|
|
|
convertType structs t1 =
|
|
|
|
|
case Map.lookup tf1 structs of
|
|
|
|
|
Nothing -> t1
|
2019-04-09 03:28:33 +02:00
|
|
|
Just (t2, _) -> tf2 (rs1 ++ rs2)
|
2019-03-06 06:51:09 +01:00
|
|
|
where (tf2, rs2) = typeRanges t2
|
|
|
|
|
where (tf1, rs1) = typeRanges t1
|
|
|
|
|
|
2019-04-22 08:48:22 +02:00
|
|
|
-- writes down the names of called functions
|
|
|
|
|
collectCallsM :: Expr -> Writer Idents ()
|
2019-04-24 09:37:47 +02:00
|
|
|
collectCallsM (Call Nothing f _) = tell $ Set.singleton f
|
2019-04-22 08:48:22 +02:00
|
|
|
collectCallsM _ = return ()
|
2019-03-06 06:51:09 +01:00
|
|
|
|
2019-04-22 19:58:14 +02:00
|
|
|
collectTFArgsM :: ModuleItem -> Writer Types ()
|
|
|
|
|
collectTFArgsM (MIPackageItem item) = do
|
|
|
|
|
_ <- case item of
|
|
|
|
|
Function _ t f decls _ -> do
|
|
|
|
|
tell $ Map.singleton f t
|
|
|
|
|
mapM (collect f) (zip [0..] decls)
|
|
|
|
|
Task _ f decls _ ->
|
|
|
|
|
mapM (collect f) (zip [0..] decls)
|
|
|
|
|
_ -> return []
|
|
|
|
|
return ()
|
|
|
|
|
where
|
|
|
|
|
collect :: Identifier -> (Int, Decl) -> Writer Types ()
|
|
|
|
|
collect f (idx, (Variable _ t x _ _)) = do
|
|
|
|
|
tell $ Map.singleton (f ++ ":" ++ show idx) t
|
|
|
|
|
tell $ Map.singleton (f ++ ":" ++ x) t
|
|
|
|
|
collect _ _ = return ()
|
|
|
|
|
collectTFArgsM _ = return ()
|
|
|
|
|
|
2019-04-22 08:33:24 +02:00
|
|
|
-- write down the types of declarations
|
2019-08-07 05:11:06 +02:00
|
|
|
traverseDeclM :: Structs -> Decl -> State Types Decl
|
|
|
|
|
traverseDeclM structs origDecl = do
|
2019-04-22 08:33:24 +02:00
|
|
|
case origDecl of
|
2019-08-07 05:11:06 +02:00
|
|
|
Variable d t x a me -> do
|
2019-04-23 21:37:47 +02:00
|
|
|
let (tf, rs) = typeRanges t
|
2019-09-25 03:48:10 +02:00
|
|
|
if isRangeable t
|
|
|
|
|
then modify $ Map.insert x (tf $ a ++ rs)
|
|
|
|
|
else return ()
|
2019-08-07 05:11:06 +02:00
|
|
|
case me of
|
|
|
|
|
Nothing -> return origDecl
|
|
|
|
|
Just e -> do
|
|
|
|
|
e' <- convertDeclExpr x e
|
|
|
|
|
return $ Variable d t x a (Just e')
|
2019-09-07 04:29:14 +02:00
|
|
|
Param s t x e -> do
|
2019-08-07 05:11:06 +02:00
|
|
|
modify $ Map.insert x t
|
|
|
|
|
e' <- convertDeclExpr x e
|
2019-09-07 04:29:14 +02:00
|
|
|
return $ Param s t x e'
|
|
|
|
|
ParamType s x mt ->
|
|
|
|
|
return $ ParamType s x mt
|
2019-08-07 05:11:06 +02:00
|
|
|
where
|
|
|
|
|
convertDeclExpr :: Identifier -> Expr -> State Types Expr
|
|
|
|
|
convertDeclExpr x e = do
|
|
|
|
|
types <- get
|
|
|
|
|
let (LHSIdent _, e') = convertAsgn structs types (LHSIdent x, e)
|
|
|
|
|
return e'
|
2019-09-25 03:48:10 +02:00
|
|
|
isRangeable :: Type -> Bool
|
|
|
|
|
isRangeable (IntegerAtom _ _) = False
|
|
|
|
|
isRangeable (NonInteger _ ) = False
|
|
|
|
|
isRangeable _ = True
|
2019-03-06 06:51:09 +01:00
|
|
|
|
2019-04-22 08:48:22 +02:00
|
|
|
-- produces a function which packs the components of a struct literal
|
|
|
|
|
packerFn :: TypeFunc -> ModuleItem
|
|
|
|
|
packerFn structTf =
|
|
|
|
|
MIPackageItem $
|
|
|
|
|
Function Nothing (structTf []) fnName decls [retStmt]
|
|
|
|
|
where
|
2019-10-15 04:01:52 +02:00
|
|
|
Struct _ fields [] = structTf []
|
2019-04-22 08:48:22 +02:00
|
|
|
toInput (t, x) = Variable Input t x [] Nothing
|
|
|
|
|
decls = map toInput fields
|
|
|
|
|
retStmt = Return $ Concat $ map (Ident . snd) fields
|
|
|
|
|
fnName = packerFnName structTf
|
|
|
|
|
|
2019-04-22 03:56:23 +02:00
|
|
|
-- returns a "unique" name for the packer for a given struct type
|
|
|
|
|
packerFnName :: TypeFunc -> Identifier
|
|
|
|
|
packerFnName structTf =
|
2019-09-04 05:52:22 +02:00
|
|
|
"sv2v_struct_" ++ shortHash structTf
|
2019-04-22 03:56:23 +02:00
|
|
|
|
2019-05-15 15:55:15 +02:00
|
|
|
-- This is where the magic happens. This is responsible for converting struct
|
2019-04-22 08:48:22 +02:00
|
|
|
-- accesses, assignments, and literals, given appropriate information about the
|
|
|
|
|
-- structs and the current declaration context. The general strategy involves
|
|
|
|
|
-- looking at the innermost type of a node to convert outer uses of fields, and
|
2019-05-15 15:55:15 +02:00
|
|
|
-- then using the outermost type to figure out the corresponding struct
|
|
|
|
|
-- definition for struct literals that are encountered.
|
2019-03-06 06:51:09 +01:00
|
|
|
convertAsgn :: Structs -> Types -> (LHS, Expr) -> (LHS, Expr)
|
|
|
|
|
convertAsgn structs types (lhs, expr) =
|
|
|
|
|
(lhs', expr')
|
|
|
|
|
where
|
|
|
|
|
(typ, lhs') = convertLHS lhs
|
|
|
|
|
expr' = snd $ convertSubExpr $ convertExpr typ expr
|
|
|
|
|
|
|
|
|
|
-- converting LHSs by looking at the innermost types first
|
|
|
|
|
convertLHS :: LHS -> (Type, LHS)
|
|
|
|
|
convertLHS (LHSIdent x) =
|
|
|
|
|
case Map.lookup x types of
|
2019-03-22 21:57:13 +01:00
|
|
|
Nothing -> (Implicit Unspecified [], LHSIdent x)
|
2019-03-06 06:51:09 +01:00
|
|
|
Just t -> (t, LHSIdent x)
|
|
|
|
|
convertLHS (LHSBit l e) =
|
2019-04-09 03:28:33 +02:00
|
|
|
case l' of
|
|
|
|
|
LHSRange lInner NonIndexed (_, loI) ->
|
2019-04-23 07:16:57 +02:00
|
|
|
(t', LHSBit lInner (simplify $ BinOp Add loI e))
|
2019-04-09 03:28:33 +02:00
|
|
|
LHSRange lInner IndexedPlus (baseI, _) ->
|
2019-04-23 07:16:57 +02:00
|
|
|
(t', LHSBit lInner (simplify $ BinOp Add baseI e))
|
|
|
|
|
_ -> (t', LHSBit l' e)
|
2019-03-06 06:51:09 +01:00
|
|
|
where
|
|
|
|
|
(t, l') = convertLHS l
|
2019-04-09 03:28:33 +02:00
|
|
|
t' = case typeRanges t of
|
|
|
|
|
(_, []) -> Implicit Unspecified []
|
|
|
|
|
(tf, rs) -> tf $ tail rs
|
2019-04-23 07:16:57 +02:00
|
|
|
convertLHS (LHSRange lOuter NonIndexed rOuter) =
|
2019-04-09 03:28:33 +02:00
|
|
|
case lOuter' of
|
2019-04-05 19:53:52 +02:00
|
|
|
LHSRange lInner NonIndexed (_, loI) ->
|
2019-04-09 03:28:33 +02:00
|
|
|
(t, LHSRange lInner NonIndexed (simplify hi, simplify lo))
|
2019-03-31 23:35:00 +02:00
|
|
|
where
|
|
|
|
|
lo = BinOp Add loI loO
|
2019-04-01 08:26:40 +02:00
|
|
|
hi = BinOp Add loI hiO
|
2019-04-09 03:28:33 +02:00
|
|
|
LHSRange lInner IndexedPlus (baseI, _) ->
|
|
|
|
|
(t, LHSRange lInner IndexedPlus (simplify base, simplify len))
|
|
|
|
|
where
|
|
|
|
|
base = BinOp Add baseI loO
|
|
|
|
|
len = rangeSize rOuter
|
|
|
|
|
_ -> (t, LHSRange lOuter' NonIndexed rOuter)
|
2019-03-06 06:51:09 +01:00
|
|
|
where
|
2019-04-23 07:16:57 +02:00
|
|
|
(hiO, loO) = rOuter
|
2019-04-09 03:28:33 +02:00
|
|
|
(t, lOuter') = convertLHS lOuter
|
|
|
|
|
convertLHS (LHSRange l m r) =
|
2019-04-23 07:16:57 +02:00
|
|
|
(t', LHSRange l' m r)
|
2019-04-09 03:28:33 +02:00
|
|
|
where
|
|
|
|
|
(t, l') = convertLHS l
|
|
|
|
|
t' = case typeRanges t of
|
|
|
|
|
(_, []) -> Implicit Unspecified []
|
|
|
|
|
(tf, rs) -> tf $ tail rs
|
2019-03-06 06:51:09 +01:00
|
|
|
convertLHS (LHSDot l x ) =
|
|
|
|
|
case t of
|
2019-03-22 21:57:13 +01:00
|
|
|
InterfaceT _ _ _ -> (Implicit Unspecified [], LHSDot l' x)
|
2019-08-09 05:12:49 +02:00
|
|
|
Struct p fields [] -> undot (Struct p fields) fields
|
|
|
|
|
Union p fields [] -> undot (Union p fields) fields
|
|
|
|
|
Implicit sg _ -> (Implicit sg [], LHSDot l' x)
|
|
|
|
|
_ -> error $ "convertLHS encountered dot for bad type: " ++ show (t, l, x)
|
|
|
|
|
where
|
|
|
|
|
(t, l') = convertLHS l
|
|
|
|
|
undot structTf fields = case Map.lookup structTf structs of
|
2019-03-06 06:51:09 +01:00
|
|
|
Nothing -> (fieldType, LHSDot l' x)
|
2019-04-05 19:53:52 +02:00
|
|
|
Just (structT, m) -> (tf [tr], LHSRange l' NonIndexed r)
|
2019-03-06 06:51:09 +01:00
|
|
|
where
|
|
|
|
|
(tf, _) = typeRanges structT
|
|
|
|
|
(r @ (hi, lo), base) = m Map.! x
|
|
|
|
|
hi' = BinOp Add base $ BinOp Sub hi lo
|
|
|
|
|
lo' = base
|
|
|
|
|
tr = (simplify hi', simplify lo')
|
2019-08-09 05:12:49 +02:00
|
|
|
where
|
|
|
|
|
fieldType = lookupFieldType fields x
|
2019-03-06 06:51:09 +01:00
|
|
|
convertLHS (LHSConcat lhss) =
|
2019-03-22 21:57:13 +01:00
|
|
|
(Implicit Unspecified [], LHSConcat $ map (snd . convertLHS) lhss)
|
2019-09-03 02:46:35 +02:00
|
|
|
convertLHS (LHSStream o e lhss) =
|
|
|
|
|
(Implicit Unspecified [], LHSStream o e $ map (snd . convertLHS) lhss)
|
2019-03-06 06:51:09 +01:00
|
|
|
|
2019-10-14 01:01:42 +02:00
|
|
|
specialTag = ':'
|
|
|
|
|
defaultKey = specialTag : "default"
|
2019-09-11 19:30:09 +02:00
|
|
|
|
2019-03-06 06:51:09 +01:00
|
|
|
-- try expression conversion by looking at the *outermost* type first
|
|
|
|
|
convertExpr :: Type -> Expr -> Expr
|
2019-03-31 20:58:47 +02:00
|
|
|
-- TODO: This is really a conversion for using default patterns to
|
|
|
|
|
-- populate arrays. Maybe this should be somewhere else?
|
2019-10-14 01:01:42 +02:00
|
|
|
convertExpr (IntegerVector t sg (r:rs)) (Pattern [(":default", e)]) =
|
2019-03-31 20:58:47 +02:00
|
|
|
Repeat (rangeSize r) [e']
|
|
|
|
|
where e' = convertExpr (IntegerVector t sg rs) e
|
2019-10-15 04:01:52 +02:00
|
|
|
convertExpr (Struct packing fields (_:rs)) (Concat exprs) =
|
|
|
|
|
Concat $ map (convertExpr (Struct packing fields rs)) exprs
|
|
|
|
|
convertExpr (Struct packing fields (_:rs)) (Bit e _) =
|
|
|
|
|
convertExpr (Struct packing fields rs) e
|
|
|
|
|
convertExpr (Struct packing fields []) (Pattern [("", Repeat (Number nStr) exprs)]) =
|
|
|
|
|
case readNumber nStr of
|
|
|
|
|
Just n -> convertExpr (Struct packing fields []) $ Pattern $
|
|
|
|
|
zip (repeat "") (concat $ take n $ repeat exprs)
|
|
|
|
|
Nothing ->
|
|
|
|
|
error $ "unable to handle repeat in pattern: " ++
|
|
|
|
|
(show $ Repeat (Number nStr) exprs)
|
|
|
|
|
convertExpr (Struct packing fields []) (Pattern itemsOrig) =
|
2019-10-14 01:01:42 +02:00
|
|
|
if extraNames /= Set.empty then
|
|
|
|
|
error $ "pattern " ++ show (Pattern itemsOrig) ++
|
|
|
|
|
" has extra named fields: " ++
|
|
|
|
|
show (Set.toList extraNames) ++ " that are not in " ++
|
|
|
|
|
show structTf
|
|
|
|
|
else if Map.member structTf structs then
|
|
|
|
|
Call Nothing
|
|
|
|
|
(packerFnName structTf)
|
|
|
|
|
(Args (map (Just . snd) items) [])
|
2019-04-11 00:33:33 +02:00
|
|
|
else
|
2019-10-14 01:01:42 +02:00
|
|
|
Pattern items
|
2019-03-06 06:51:09 +01:00
|
|
|
where
|
2019-10-15 04:01:52 +02:00
|
|
|
structTf = Struct packing fields
|
2019-10-14 01:01:42 +02:00
|
|
|
fieldNames = map snd fields
|
|
|
|
|
fieldTypeMap = Map.fromList $ map swap fields
|
|
|
|
|
|
2019-04-11 00:33:33 +02:00
|
|
|
itemsNamed =
|
2019-10-14 01:01:42 +02:00
|
|
|
-- patterns either use positions based or name/type/default
|
|
|
|
|
if all ((/= "") . fst) itemsOrig then
|
|
|
|
|
itemsOrig
|
|
|
|
|
-- position-based patterns should cover every field
|
|
|
|
|
else if length itemsOrig /= length fields then
|
2019-10-15 04:01:52 +02:00
|
|
|
error $ "struct pattern " ++ show (Pattern itemsOrig) ++
|
2019-10-14 01:01:42 +02:00
|
|
|
" doesn't have the same # of items as " ++
|
|
|
|
|
show structTf
|
2019-03-06 06:51:09 +01:00
|
|
|
-- if the pattern does not use identifiers, use the
|
|
|
|
|
-- identifiers from the struct type definition in order
|
2019-09-11 19:30:09 +02:00
|
|
|
else
|
2019-10-14 01:01:42 +02:00
|
|
|
zip fieldNames (map snd itemsOrig)
|
|
|
|
|
(specialItems, namedItems) =
|
|
|
|
|
partition ((== specialTag) . head . fst) itemsNamed
|
|
|
|
|
namedItemMap = Map.fromList namedItems
|
|
|
|
|
specialItemMap = Map.fromList specialItems
|
|
|
|
|
|
|
|
|
|
extraNames = Set.difference
|
|
|
|
|
(Set.fromList $ map fst namedItems)
|
|
|
|
|
(Map.keysSet fieldTypeMap)
|
|
|
|
|
|
|
|
|
|
items = zip fieldNames $ map resolveField fieldNames
|
|
|
|
|
resolveField :: Identifier -> Expr
|
|
|
|
|
resolveField fieldName =
|
|
|
|
|
convertExpr fieldType $
|
|
|
|
|
-- look up by name
|
|
|
|
|
if Map.member fieldName namedItemMap then
|
|
|
|
|
namedItemMap Map.! fieldName
|
2019-10-14 05:37:43 +02:00
|
|
|
-- recurse for substructures
|
|
|
|
|
else if isStruct fieldType then
|
|
|
|
|
Pattern specialItems
|
2019-10-14 01:01:42 +02:00
|
|
|
-- look up by field type
|
|
|
|
|
else if Map.member fieldTypeName specialItemMap then
|
|
|
|
|
specialItemMap Map.! fieldTypeName
|
|
|
|
|
-- fall back on the default value
|
|
|
|
|
else if Map.member defaultKey specialItemMap then
|
|
|
|
|
specialItemMap Map.! defaultKey
|
|
|
|
|
else
|
|
|
|
|
error $ "couldn't find field " ++ fieldName ++
|
|
|
|
|
" from struct definition " ++ show structTf ++
|
|
|
|
|
" in struct pattern " ++ show itemsOrig
|
|
|
|
|
where
|
|
|
|
|
fieldType = fieldTypeMap Map.! fieldName
|
|
|
|
|
fieldTypeName =
|
|
|
|
|
specialTag : (show $ fst $ typeRanges fieldType)
|
2019-10-14 05:37:43 +02:00
|
|
|
isStruct :: Type -> Bool
|
|
|
|
|
isStruct (Struct{}) = True
|
|
|
|
|
isStruct _ = False
|
2019-10-14 01:01:42 +02:00
|
|
|
|
2019-10-15 04:01:52 +02:00
|
|
|
convertExpr (Struct packing fields (r : rs)) subExpr =
|
2019-10-14 01:01:42 +02:00
|
|
|
Repeat (rangeSize r) [subExpr']
|
|
|
|
|
where
|
2019-10-15 04:01:52 +02:00
|
|
|
structTf = Struct packing fields
|
2019-10-14 01:01:42 +02:00
|
|
|
subExpr' = convertExpr (structTf rs) subExpr
|
2019-03-06 06:51:09 +01:00
|
|
|
convertExpr _ other = other
|
|
|
|
|
|
|
|
|
|
-- try expression conversion by looking at the *innermost* type first
|
|
|
|
|
convertSubExpr :: Expr -> (Type, Expr)
|
|
|
|
|
convertSubExpr (Ident x) =
|
|
|
|
|
case Map.lookup x types of
|
2019-03-22 21:57:13 +01:00
|
|
|
Nothing -> (Implicit Unspecified [], Ident x)
|
2019-03-06 06:51:09 +01:00
|
|
|
Just t -> (t, Ident x)
|
2019-03-23 00:24:45 +01:00
|
|
|
convertSubExpr (Dot e x) =
|
2019-03-08 02:03:35 +01:00
|
|
|
case subExprType of
|
2019-08-09 05:12:49 +02:00
|
|
|
Struct p fields [] -> undot (Struct p fields) fields
|
|
|
|
|
Union p fields [] -> undot (Union p fields) fields
|
2019-03-23 00:24:45 +01:00
|
|
|
_ -> (Implicit Unspecified [], Dot e' x)
|
2019-03-06 06:51:09 +01:00
|
|
|
where
|
|
|
|
|
(subExprType, e') = convertSubExpr e
|
2019-08-09 05:12:49 +02:00
|
|
|
undot structTf fields =
|
|
|
|
|
if Map.notMember structTf structs
|
|
|
|
|
then (fieldType, Dot e' x)
|
|
|
|
|
else (fieldType, Range e' NonIndexed r)
|
|
|
|
|
where
|
|
|
|
|
fieldType = lookupFieldType fields x
|
|
|
|
|
r = lookupUnstructRange structTf x
|
2019-04-09 03:28:33 +02:00
|
|
|
convertSubExpr (Range eOuter NonIndexed (rOuter @ (hiO, loO))) =
|
2019-03-06 06:51:09 +01:00
|
|
|
-- VCS doesn't allow ranges to be cascaded, so we need to combine
|
|
|
|
|
-- nested Ranges into a single range. My understanding of the
|
2019-03-31 23:35:00 +02:00
|
|
|
-- semantics are that a range returns a new, zero-indexed sub-range.
|
2019-03-06 06:51:09 +01:00
|
|
|
case eOuter' of
|
2019-04-05 19:53:52 +02:00
|
|
|
Range eInner NonIndexed (_, loI) ->
|
2019-04-09 03:28:33 +02:00
|
|
|
(t, Range eInner NonIndexed (simplify hi, simplify lo))
|
2019-03-06 06:51:09 +01:00
|
|
|
where
|
|
|
|
|
lo = BinOp Add loI loO
|
2019-04-01 08:26:40 +02:00
|
|
|
hi = BinOp Add loI hiO
|
2019-04-09 03:28:33 +02:00
|
|
|
Range eInner IndexedPlus (baseI, _) ->
|
|
|
|
|
(t, Range eInner IndexedPlus (simplify base, simplify len))
|
|
|
|
|
where
|
|
|
|
|
base = BinOp Add baseI loO
|
|
|
|
|
len = rangeSize rOuter
|
|
|
|
|
_ -> (t, Range eOuter' NonIndexed rOuter)
|
2019-03-06 06:51:09 +01:00
|
|
|
where (t, eOuter') = convertSubExpr eOuter
|
2019-04-09 03:28:33 +02:00
|
|
|
convertSubExpr (Range e m r) =
|
|
|
|
|
(t', Range e' m r)
|
|
|
|
|
where
|
|
|
|
|
(t, e') = convertSubExpr e
|
|
|
|
|
t' = case typeRanges t of
|
|
|
|
|
(_, []) -> Implicit Unspecified []
|
|
|
|
|
(tf, rs) -> tf $ tail rs
|
2019-03-06 06:51:09 +01:00
|
|
|
convertSubExpr (Concat exprs) =
|
2019-03-22 21:57:13 +01:00
|
|
|
(Implicit Unspecified [], Concat $ map (snd . convertSubExpr) exprs)
|
2019-09-02 00:42:13 +02:00
|
|
|
convertSubExpr (Stream o e exprs) =
|
|
|
|
|
(Implicit Unspecified [], Stream o e' exprs')
|
|
|
|
|
where
|
|
|
|
|
e' = (snd . convertSubExpr) e
|
|
|
|
|
exprs' = map (snd . convertSubExpr) exprs
|
2019-03-06 06:51:09 +01:00
|
|
|
convertSubExpr (BinOp op e1 e2) =
|
2019-03-22 21:57:13 +01:00
|
|
|
(Implicit Unspecified [], BinOp op e1' e2')
|
2019-03-06 06:51:09 +01:00
|
|
|
where
|
|
|
|
|
(_, e1') = convertSubExpr e1
|
|
|
|
|
(_, e2') = convertSubExpr e2
|
2019-03-31 23:00:55 +02:00
|
|
|
convertSubExpr (Bit e i) =
|
2019-03-31 23:35:00 +02:00
|
|
|
case e' of
|
2019-04-05 19:53:52 +02:00
|
|
|
Range eInner NonIndexed (_, loI) ->
|
2019-03-31 23:35:00 +02:00
|
|
|
(t', Bit eInner (simplify $ BinOp Add loI i'))
|
2019-04-09 03:28:33 +02:00
|
|
|
Range eInner IndexedPlus (baseI, _) ->
|
|
|
|
|
(t', Bit eInner (simplify $ BinOp Add baseI i'))
|
2019-03-31 23:35:00 +02:00
|
|
|
_ -> (t', Bit e' i')
|
2019-03-31 23:00:55 +02:00
|
|
|
where
|
|
|
|
|
(t, e') = convertSubExpr e
|
|
|
|
|
t' = case typeRanges t of
|
|
|
|
|
(_, []) -> Implicit Unspecified []
|
|
|
|
|
(tf, rs) -> tf $ tail rs
|
|
|
|
|
(_, i') = convertSubExpr i
|
2019-04-24 09:37:47 +02:00
|
|
|
convertSubExpr (Call Nothing f args) =
|
|
|
|
|
(retType, uncurry (Call Nothing) $ convertCall structs types f args)
|
2019-04-22 19:58:14 +02:00
|
|
|
where
|
|
|
|
|
retType = case Map.lookup f types of
|
|
|
|
|
Nothing -> Implicit Unspecified []
|
|
|
|
|
Just t -> t
|
2019-05-16 16:51:57 +02:00
|
|
|
convertSubExpr (Call (Just x) f args) =
|
|
|
|
|
(Implicit Unspecified [], Call (Just x) f args)
|
|
|
|
|
convertSubExpr (String s) = (Implicit Unspecified [], String s)
|
|
|
|
|
convertSubExpr (Number n) = (Implicit Unspecified [], Number n)
|
2019-10-07 03:21:58 +02:00
|
|
|
convertSubExpr (Time n) = (Implicit Unspecified [], Time n)
|
2019-05-16 16:51:57 +02:00
|
|
|
convertSubExpr (PSIdent x y) = (Implicit Unspecified [], PSIdent x y)
|
|
|
|
|
convertSubExpr (Repeat e es) =
|
|
|
|
|
(Implicit Unspecified [], Repeat e' es')
|
|
|
|
|
where
|
|
|
|
|
(_, e') = convertSubExpr e
|
|
|
|
|
es' = map (snd . convertSubExpr) es
|
|
|
|
|
convertSubExpr (UniOp op e) =
|
|
|
|
|
(Implicit Unspecified [], UniOp op e')
|
|
|
|
|
where (_, e') = convertSubExpr e
|
|
|
|
|
convertSubExpr (Mux a b c) =
|
|
|
|
|
(t, Mux a' b' c')
|
|
|
|
|
where
|
|
|
|
|
(_, a') = convertSubExpr a
|
|
|
|
|
(t, b') = convertSubExpr b
|
|
|
|
|
(_, c') = convertSubExpr c
|
|
|
|
|
convertSubExpr (Cast (Left t) sub) =
|
|
|
|
|
(t, Cast (Left t) (snd $ convertSubExpr sub))
|
|
|
|
|
convertSubExpr (Cast (Right e) sub) =
|
|
|
|
|
(Implicit Unspecified [], Cast (Right e) (snd $ convertSubExpr sub))
|
2019-09-14 18:31:44 +02:00
|
|
|
convertSubExpr (DimsFn f tore) =
|
|
|
|
|
(Implicit Unspecified [], DimsFn f tore')
|
|
|
|
|
where tore' = convertTypeOrExpr tore
|
|
|
|
|
convertSubExpr (DimFn f tore e) =
|
|
|
|
|
(Implicit Unspecified [], DimFn f tore' e')
|
|
|
|
|
where
|
|
|
|
|
tore' = convertTypeOrExpr tore
|
|
|
|
|
e' = snd $ convertSubExpr e
|
2019-05-16 16:51:57 +02:00
|
|
|
convertSubExpr (Pattern items) =
|
2019-10-14 01:01:42 +02:00
|
|
|
if all (== "") $ map fst items'
|
2019-09-03 04:35:36 +02:00
|
|
|
then (Implicit Unspecified [], Concat $ map snd items')
|
|
|
|
|
else (Implicit Unspecified [], Pattern items')
|
2019-05-16 16:51:57 +02:00
|
|
|
where
|
|
|
|
|
items' = map mapItem items
|
|
|
|
|
mapItem (mx, e) = (mx, snd $ convertSubExpr e)
|
2019-10-06 22:13:34 +02:00
|
|
|
convertSubExpr (MinTypMax a b c) =
|
|
|
|
|
(t, MinTypMax a' b' c')
|
|
|
|
|
where
|
|
|
|
|
(_, a') = convertSubExpr a
|
|
|
|
|
(t, b') = convertSubExpr b
|
|
|
|
|
(_, c') = convertSubExpr c
|
2019-09-09 07:38:14 +02:00
|
|
|
convertSubExpr Nil = (Implicit Unspecified [], Nil)
|
2019-03-06 06:51:09 +01:00
|
|
|
|
2019-09-14 18:31:44 +02:00
|
|
|
convertTypeOrExpr :: TypeOrExpr -> TypeOrExpr
|
|
|
|
|
convertTypeOrExpr (Left t) = Left t
|
|
|
|
|
convertTypeOrExpr (Right e) = Right $ snd $ convertSubExpr e
|
|
|
|
|
|
2019-03-06 06:51:09 +01:00
|
|
|
-- lookup the range of a field in its unstructured type
|
|
|
|
|
lookupUnstructRange :: TypeFunc -> Identifier -> Range
|
|
|
|
|
lookupUnstructRange structTf fieldName =
|
2019-08-27 02:20:38 +02:00
|
|
|
case Map.lookup fieldName fieldRangeMap of
|
|
|
|
|
Nothing -> error $ "field '" ++ fieldName ++
|
|
|
|
|
"' not found in struct: " ++ show structTf
|
|
|
|
|
Just r -> r
|
2019-03-06 06:51:09 +01:00
|
|
|
where fieldRangeMap = Map.map fst $ snd $ structs Map.! structTf
|
|
|
|
|
|
|
|
|
|
-- lookup the type of a field in the given field list
|
|
|
|
|
lookupFieldType :: [(Type, Identifier)] -> Identifier -> Type
|
|
|
|
|
lookupFieldType fields fieldName = fieldMap Map.! fieldName
|
|
|
|
|
where fieldMap = Map.fromList $ map swap fields
|
2019-04-22 19:58:14 +02:00
|
|
|
|
|
|
|
|
-- attempts to convert based on the assignment-like contexts of TF arguments
|
|
|
|
|
convertCall :: Structs -> Types -> Identifier -> Args -> (Identifier, Args)
|
|
|
|
|
convertCall structs types f (Args pnArgs kwArgs) =
|
|
|
|
|
(f, args)
|
|
|
|
|
where
|
|
|
|
|
idxs = map show ([0..] :: [Int])
|
|
|
|
|
args = Args
|
|
|
|
|
(map snd $ map convertArg $ zip idxs pnArgs)
|
|
|
|
|
(map convertArg kwArgs)
|
|
|
|
|
convertArg :: (Identifier, Maybe Expr) -> (Identifier, Maybe Expr)
|
|
|
|
|
convertArg (x, Nothing) = (x, Nothing)
|
|
|
|
|
convertArg (x, Just e ) = (x, Just e')
|
|
|
|
|
where
|
|
|
|
|
(_, e') = convertAsgn structs types
|
|
|
|
|
(LHSIdent $ f ++ ":" ++ x, e)
|
|
|
|
|
|