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
|
|
|
|
|
|
2020-07-03 02:50:26 +02:00
|
|
|
import Control.Monad ((>=>), when)
|
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
|
|
|
|
2020-07-12 23:06:27 +02:00
|
|
|
import Convert.ExprUtils
|
2020-07-03 02:50:26 +02:00
|
|
|
import Convert.Scoper
|
2019-03-06 06:51:09 +01:00
|
|
|
import Convert.Traverse
|
|
|
|
|
import Language.SystemVerilog.AST
|
|
|
|
|
|
2020-07-03 02:50:26 +02:00
|
|
|
type StructInfo = (Type, Map.Map Identifier Range)
|
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
|
2020-06-21 04:39:13 +02:00
|
|
|
convertDescription (description @ (Part _ _ Module _ _ _ _)) =
|
2020-07-16 02:44:57 +02:00
|
|
|
traverseModuleItems
|
|
|
|
|
(traverseTypes' ExcludeParamTypes $ traverseNestedTypes convertType) $
|
2020-07-03 02:50:26 +02:00
|
|
|
partScoper traverseDeclM traverseModuleItemM traverseGenItemM traverseStmtM
|
|
|
|
|
description
|
2019-04-22 07:18:25 +02:00
|
|
|
convertDescription other = other
|
2019-04-22 04:22:33 +02:00
|
|
|
|
2020-07-02 06:37:19 +02:00
|
|
|
convertStruct :: Type -> Maybe StructInfo
|
|
|
|
|
convertStruct (Struct Unpacked fields _) =
|
|
|
|
|
convertStruct' True Unspecified fields
|
|
|
|
|
convertStruct (Struct (Packed sg) fields _) =
|
|
|
|
|
convertStruct' True sg fields
|
|
|
|
|
convertStruct (Union (Packed sg) fields _) =
|
|
|
|
|
convertStruct' False sg fields
|
|
|
|
|
convertStruct _ = Nothing
|
|
|
|
|
|
|
|
|
|
convertStruct' :: Bool -> Signing -> [Field] -> Maybe StructInfo
|
|
|
|
|
convertStruct' isStruct sg fields =
|
2019-03-06 06:51:09 +01:00
|
|
|
if canUnstructure
|
2020-07-02 06:37:19 +02:00
|
|
|
then Just (unstructType, unstructFields)
|
|
|
|
|
else Nothing
|
2019-03-06 06:51:09 +01:00
|
|
|
where
|
2020-07-12 23:06:27 +02:00
|
|
|
zero = RawNum 0
|
2019-03-06 06:51:09 +01:00
|
|
|
typeRange :: Type -> Range
|
|
|
|
|
typeRange t =
|
2019-11-20 05:15:22 +01:00
|
|
|
case ranges of
|
|
|
|
|
[] -> (zero, zero)
|
|
|
|
|
[range] -> range
|
|
|
|
|
_ -> error "Struct.hs invariant failure"
|
2019-03-06 06:51:09 +01:00
|
|
|
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
|
2020-07-12 23:06:27 +02:00
|
|
|
then map simplify $ tail $ scanr (BinOp Add) (RawNum 0) fieldSizes
|
|
|
|
|
else map simplify $ repeat (RawNum 0)
|
2019-08-09 05:12:49 +02:00
|
|
|
fieldHis =
|
|
|
|
|
if isStruct
|
2020-07-09 05:49:46 +02:00
|
|
|
then map simplify $ init $ scanr (BinOp Add) minusOne fieldSizes
|
|
|
|
|
else map simplify $ map (BinOp Add minusOne) fieldSizes
|
2020-07-12 23:06:27 +02:00
|
|
|
minusOne = UniOp UniSub $ RawNum 1
|
2019-03-06 06:51:09 +01:00
|
|
|
|
|
|
|
|
-- create the mapping structure for the unstructured fields
|
|
|
|
|
keys = map snd fields
|
2020-07-03 02:50:26 +02:00
|
|
|
unstructRanges = zip fieldHis fieldLos
|
|
|
|
|
unstructFields = Map.fromList $ zip keys unstructRanges
|
2019-03-06 06:51:09 +01:00
|
|
|
|
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
|
2020-07-12 23:06:27 +02:00
|
|
|
packedRange = (simplify $ BinOp Sub structSize (RawNum 1), zero)
|
2019-05-10 16:41:31 +02:00
|
|
|
unstructType = IntegerVector TLogic sg [packedRange]
|
2019-03-06 06:51:09 +01:00
|
|
|
|
2019-11-20 05:15:22 +01:00
|
|
|
-- check if this struct can be packed into an integer vector; we only
|
|
|
|
|
-- pack flat integer vector types; the fields will be flattened and
|
|
|
|
|
-- converted by other phases
|
|
|
|
|
isFlatIntVec :: Type -> Bool
|
|
|
|
|
isFlatIntVec (IntegerVector _ _ rs) = length rs <= 1
|
|
|
|
|
isFlatIntVec _ = False
|
|
|
|
|
canUnstructure = all isFlatIntVec fieldTypes
|
2019-03-06 06:51:09 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
-- convert a struct type to its unstructured equivalent
|
2020-07-02 06:37:19 +02:00
|
|
|
convertType :: Type -> Type
|
|
|
|
|
convertType t1 =
|
|
|
|
|
case convertStruct t1 of
|
2019-03-06 06:51:09 +01:00
|
|
|
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
|
2020-07-02 06:37:19 +02:00
|
|
|
where (_, rs1) = typeRanges t1
|
2019-03-06 06:51:09 +01:00
|
|
|
|
2019-04-22 08:33:24 +02:00
|
|
|
-- write down the types of declarations
|
2020-07-03 02:50:26 +02:00
|
|
|
traverseDeclM :: Decl -> Scoper Type Decl
|
|
|
|
|
traverseDeclM decl = do
|
|
|
|
|
decl' <- case decl of
|
2020-06-14 21:56:09 +02:00
|
|
|
Variable d t x a e -> do
|
2019-04-23 21:37:47 +02:00
|
|
|
let (tf, rs) = typeRanges t
|
2020-07-03 02:50:26 +02:00
|
|
|
when (isRangeable t) $
|
|
|
|
|
insertElem x (tf $ a ++ rs)
|
|
|
|
|
let e' = convertExpr t e
|
2020-06-14 21:56:09 +02:00
|
|
|
return $ Variable d t x a e'
|
2019-09-07 04:29:14 +02:00
|
|
|
Param s t x e -> do
|
2020-07-03 02:50:26 +02:00
|
|
|
insertElem x t
|
|
|
|
|
let e' = convertExpr t e
|
2019-09-07 04:29:14 +02:00
|
|
|
return $ Param s t x e'
|
2020-07-03 02:50:26 +02:00
|
|
|
ParamType{} -> return decl
|
|
|
|
|
CommentDecl{} -> return decl
|
|
|
|
|
traverseDeclExprsM traverseExprM decl'
|
2019-08-07 05:11:06 +02:00
|
|
|
where
|
2019-09-25 03:48:10 +02:00
|
|
|
isRangeable :: Type -> Bool
|
2020-07-03 02:50:26 +02:00
|
|
|
isRangeable IntegerAtom{} = False
|
|
|
|
|
isRangeable NonInteger{} = False
|
2019-09-25 03:48:10 +02:00
|
|
|
isRangeable _ = True
|
2019-03-06 06:51:09 +01:00
|
|
|
|
2020-07-03 02:50:26 +02:00
|
|
|
traverseGenItemM :: GenItem -> Scoper Type GenItem
|
|
|
|
|
traverseGenItemM = traverseGenItemExprsM traverseExprM
|
|
|
|
|
|
|
|
|
|
traverseModuleItemM :: ModuleItem -> Scoper Type ModuleItem
|
|
|
|
|
traverseModuleItemM =
|
|
|
|
|
traverseLHSsM traverseLHSM >=>
|
|
|
|
|
traverseExprsM traverseExprM >=>
|
|
|
|
|
traverseAsgnsM traverseAsgnM
|
|
|
|
|
|
|
|
|
|
traverseStmtM :: Stmt -> Scoper Type Stmt
|
|
|
|
|
traverseStmtM (Subroutine expr args) = do
|
|
|
|
|
argsMapper <- embedScopes convertCall expr
|
|
|
|
|
let args' = argsMapper args
|
|
|
|
|
let stmt' = Subroutine expr args'
|
|
|
|
|
traverseStmtM' stmt'
|
|
|
|
|
traverseStmtM stmt = traverseStmtM' stmt
|
|
|
|
|
|
|
|
|
|
traverseStmtM' :: Stmt -> Scoper Type Stmt
|
|
|
|
|
traverseStmtM' =
|
|
|
|
|
traverseStmtLHSsM traverseLHSM >=>
|
|
|
|
|
traverseStmtExprsM traverseExprM >=>
|
|
|
|
|
traverseStmtAsgnsM traverseAsgnM
|
|
|
|
|
|
|
|
|
|
traverseExprM :: Expr -> Scoper Type Expr
|
|
|
|
|
traverseExprM = traverseNestedExprsM $
|
|
|
|
|
embedScopes convertSubExpr >=> return . snd
|
|
|
|
|
|
|
|
|
|
traverseLHSM :: LHS -> Scoper Type LHS
|
|
|
|
|
traverseLHSM = traverseNestedLHSsM $ convertLHS >=> return . snd
|
|
|
|
|
|
2019-11-20 05:15:22 +01:00
|
|
|
-- removes the innermost range from the given type, if possible
|
|
|
|
|
dropInnerTypeRange :: Type -> Type
|
|
|
|
|
dropInnerTypeRange t =
|
|
|
|
|
case typeRanges t of
|
2020-07-03 02:50:26 +02:00
|
|
|
(_, []) -> unknownType
|
2019-11-20 05:15:22 +01:00
|
|
|
(tf, rs) -> tf $ tail rs
|
|
|
|
|
|
2020-07-24 02:23:40 +02:00
|
|
|
-- produces the type of the given part select, if possible
|
|
|
|
|
replaceInnerTypeRange :: PartSelectMode -> Range -> Type -> Type
|
|
|
|
|
replaceInnerTypeRange NonIndexed r t =
|
|
|
|
|
case typeRanges t of
|
|
|
|
|
(_, []) -> unknownType
|
|
|
|
|
(tf, rs) -> tf $ r : tail rs
|
|
|
|
|
replaceInnerTypeRange IndexedPlus r t =
|
|
|
|
|
replaceInnerTypeRange NonIndexed (snd r, RawNum 1) t
|
|
|
|
|
replaceInnerTypeRange IndexedMinus r t =
|
|
|
|
|
replaceInnerTypeRange NonIndexed (snd r, RawNum 1) t
|
|
|
|
|
|
2020-07-03 02:50:26 +02:00
|
|
|
unknownType :: Type
|
|
|
|
|
unknownType = Implicit Unspecified []
|
|
|
|
|
|
|
|
|
|
traverseAsgnM :: (LHS, Expr) -> Scoper Type (LHS, Expr)
|
|
|
|
|
traverseAsgnM (lhs, expr) = do
|
|
|
|
|
-- convert the LHS using the innermost type information
|
|
|
|
|
(typ, lhs') <- convertLHS lhs
|
|
|
|
|
-- convert the RHS using the LHS type information, and then the innermost
|
|
|
|
|
-- type information on the resulting RHS
|
|
|
|
|
(_, expr') <- embedScopes convertSubExpr $ convertExpr typ expr
|
|
|
|
|
return (lhs', expr')
|
|
|
|
|
|
|
|
|
|
specialTag :: Char
|
|
|
|
|
specialTag = ':'
|
|
|
|
|
defaultKey :: String
|
|
|
|
|
defaultKey = specialTag : "default"
|
|
|
|
|
|
|
|
|
|
structIsntReady :: Type -> Bool
|
|
|
|
|
structIsntReady = (Nothing ==) . convertStruct
|
|
|
|
|
|
|
|
|
|
-- try expression conversion by looking at the *outermost* type first
|
|
|
|
|
convertExpr :: Type -> Expr -> Expr
|
|
|
|
|
convertExpr _ Nil = Nil
|
|
|
|
|
convertExpr t (Mux c e1 e2) =
|
|
|
|
|
Mux c e1' e2'
|
2019-03-06 06:51:09 +01:00
|
|
|
where
|
2020-07-03 02:50:26 +02:00
|
|
|
e1' = convertExpr t e1
|
|
|
|
|
e2' = convertExpr t e2
|
2020-07-22 02:05:27 +02:00
|
|
|
|
2020-07-03 02:50:26 +02:00
|
|
|
convertExpr (struct @ (Struct _ fields [])) (Pattern itemsOrig) =
|
|
|
|
|
if extraNames /= Set.empty then
|
|
|
|
|
error $ "pattern " ++ show (Pattern itemsOrig) ++
|
|
|
|
|
" has extra named fields: " ++
|
|
|
|
|
show (Set.toList extraNames) ++ " that are not in " ++ show struct
|
|
|
|
|
else if structIsntReady struct then
|
|
|
|
|
Pattern items
|
|
|
|
|
else
|
|
|
|
|
Concat
|
|
|
|
|
$ map (uncurry $ Cast . Left)
|
|
|
|
|
$ zip (map fst fields) (map snd items)
|
|
|
|
|
where
|
|
|
|
|
fieldNames = map snd fields
|
|
|
|
|
fieldTypeMap = Map.fromList $ map swap fields
|
|
|
|
|
|
|
|
|
|
itemsNamed =
|
|
|
|
|
-- 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
|
|
|
|
|
error $ "struct pattern " ++ show (Pattern itemsOrig) ++
|
|
|
|
|
" doesn't have the same # of items as " ++ show struct
|
|
|
|
|
-- if the pattern does not use identifiers, use the
|
|
|
|
|
-- identifiers from the struct type definition in order
|
2019-04-11 00:33:33 +02:00
|
|
|
else
|
2020-07-03 02:50:26 +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
|
|
|
|
|
-- recurse for substructures
|
|
|
|
|
else if isStruct fieldType then
|
|
|
|
|
Pattern specialItems
|
|
|
|
|
-- 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 struct ++
|
|
|
|
|
" in struct pattern " ++ show itemsOrig
|
2019-11-20 05:15:22 +01:00
|
|
|
where
|
2020-07-03 02:50:26 +02:00
|
|
|
fieldType = fieldTypeMap Map.! fieldName
|
|
|
|
|
fieldTypeName =
|
|
|
|
|
specialTag : (show $ fst $ typeRanges fieldType)
|
|
|
|
|
isStruct :: Type -> Bool
|
|
|
|
|
isStruct (Struct{}) = True
|
|
|
|
|
isStruct _ = False
|
|
|
|
|
|
2020-07-22 02:05:27 +02:00
|
|
|
convertExpr (Implicit _ []) expr = expr
|
|
|
|
|
convertExpr (Implicit sg rs) expr =
|
|
|
|
|
convertExpr (IntegerVector TBit sg rs) expr
|
|
|
|
|
|
|
|
|
|
-- TODO: This is a conversion for concat array literals with elements
|
|
|
|
|
-- that are unsized numbers. This probably belongs somewhere else.
|
|
|
|
|
convertExpr (t @ IntegerVector{}) (Concat exprs) =
|
|
|
|
|
if all isUnsizedNumber exprs
|
|
|
|
|
then Concat $ map (Cast $ Left t') exprs
|
|
|
|
|
else Concat $ map (convertExpr t') exprs
|
2020-07-03 02:50:26 +02:00
|
|
|
where
|
2020-07-22 02:05:27 +02:00
|
|
|
t' = dropInnerTypeRange t
|
|
|
|
|
isUnsizedNumber :: Expr -> Bool
|
|
|
|
|
isUnsizedNumber (Number n) = not $ numberIsSized n
|
2021-02-03 22:12:05 +01:00
|
|
|
isUnsizedNumber (UniOp _ e) = isUnsizedNumber e
|
|
|
|
|
isUnsizedNumber (BinOp _ e1 e2) =
|
|
|
|
|
isUnsizedNumber e1 || isUnsizedNumber e2
|
2020-07-22 02:05:27 +02:00
|
|
|
isUnsizedNumber _ = False
|
|
|
|
|
|
|
|
|
|
-- TODO: This is really a conversion for using default patterns to
|
|
|
|
|
-- populate arrays. Maybe this should be somewhere else?
|
|
|
|
|
convertExpr t (orig @ (Pattern [(":default", expr)])) =
|
|
|
|
|
if null rs
|
|
|
|
|
then orig
|
|
|
|
|
else Repeat count [expr']
|
2020-07-03 02:50:26 +02:00
|
|
|
where
|
2020-07-22 02:05:27 +02:00
|
|
|
count = rangeSize $ head rs
|
|
|
|
|
expr' = Cast (Left t') $ convertExpr t' expr
|
|
|
|
|
(_, rs) = typeRanges t
|
|
|
|
|
t' = dropInnerTypeRange t
|
|
|
|
|
|
|
|
|
|
-- pattern syntax used for simple array literals
|
|
|
|
|
convertExpr t (Pattern items) =
|
|
|
|
|
if all null names
|
|
|
|
|
then convertExpr t $ Concat exprs'
|
|
|
|
|
else Pattern items
|
|
|
|
|
where
|
|
|
|
|
(names, exprs) = unzip items
|
|
|
|
|
t' = dropInnerTypeRange t
|
|
|
|
|
exprs' = map (convertExpr t') exprs
|
|
|
|
|
|
|
|
|
|
-- propagate types through concatenation expressions
|
|
|
|
|
convertExpr t (Concat exprs) =
|
|
|
|
|
Concat exprs'
|
|
|
|
|
where
|
|
|
|
|
t' = dropInnerTypeRange t
|
|
|
|
|
exprs' = map (convertExpr t') exprs
|
|
|
|
|
|
2020-07-03 02:50:26 +02:00
|
|
|
convertExpr _ other = other
|
|
|
|
|
|
|
|
|
|
fallbackType :: Scopes Type -> Expr -> (Type, Expr)
|
|
|
|
|
fallbackType scopes e =
|
2020-07-15 06:22:41 +02:00
|
|
|
case lookupElem scopes e of
|
2020-07-03 02:50:26 +02:00
|
|
|
Nothing -> (unknownType, e)
|
|
|
|
|
Just (_, _, t) -> (t, e)
|
|
|
|
|
|
|
|
|
|
-- converting LHSs by looking at the innermost types first
|
|
|
|
|
convertLHS :: LHS -> Scoper Type (Type, LHS)
|
|
|
|
|
convertLHS l = do
|
|
|
|
|
let e = lhsToExpr l
|
|
|
|
|
(t, e') <- embedScopes convertSubExpr e
|
|
|
|
|
return $ case exprToLHS e' of
|
|
|
|
|
Just l' -> (t, l')
|
|
|
|
|
Nothing -> error $ "struct conversion created non-LHS from "
|
|
|
|
|
++ (show e) ++ " to " ++ (show e')
|
|
|
|
|
|
|
|
|
|
-- try expression conversion by looking at the *innermost* type first
|
|
|
|
|
convertSubExpr :: Scopes Type -> Expr -> (Type, Expr)
|
|
|
|
|
convertSubExpr scopes (Dot e x) =
|
|
|
|
|
if isntStruct subExprType then
|
|
|
|
|
fallbackType scopes $ Dot e' x
|
|
|
|
|
else if structIsntReady subExprType then
|
|
|
|
|
(fieldType, Dot e' x)
|
|
|
|
|
else
|
|
|
|
|
(fieldType, undotted)
|
|
|
|
|
where
|
|
|
|
|
(subExprType, e') = convertSubExpr scopes e
|
|
|
|
|
(fieldType, bounds, dims) = lookupFieldInfo subExprType x
|
|
|
|
|
base = fst bounds
|
|
|
|
|
len = rangeSize bounds
|
2020-07-12 23:06:27 +02:00
|
|
|
undotted = if null dims || rangeSize (head dims) == RawNum 1
|
2020-07-03 02:50:26 +02:00
|
|
|
then Bit e' (fst bounds)
|
|
|
|
|
else Range e' IndexedMinus (base, len)
|
|
|
|
|
convertSubExpr scopes (Range (Dot e x) NonIndexed rOuter) =
|
|
|
|
|
if isntStruct subExprType then
|
|
|
|
|
fallbackType scopes orig'
|
|
|
|
|
else if structIsntReady subExprType then
|
2020-07-24 02:23:40 +02:00
|
|
|
(replaceInnerTypeRange NonIndexed rOuter fieldType, orig')
|
2020-07-03 02:50:26 +02:00
|
|
|
else
|
2020-07-24 02:23:40 +02:00
|
|
|
(replaceInnerTypeRange NonIndexed rOuter fieldType, undotted)
|
2020-07-03 02:50:26 +02:00
|
|
|
where
|
|
|
|
|
(subExprType, e') = convertSubExpr scopes e
|
|
|
|
|
orig' = Range (Dot e' x) NonIndexed rOuter
|
|
|
|
|
(fieldType, bounds, dims) = lookupFieldInfo subExprType x
|
|
|
|
|
[dim] = dims
|
|
|
|
|
rangeLeft = ( BinOp Sub (fst bounds) $ BinOp Sub (fst dim) (fst rOuter)
|
2020-02-17 19:57:48 +01:00
|
|
|
, BinOp Sub (fst bounds) $ BinOp Sub (fst dim) (snd rOuter) )
|
2020-07-03 02:50:26 +02:00
|
|
|
rangeRight =( BinOp Add (snd bounds) $ BinOp Sub (snd dim) (fst rOuter)
|
2020-02-17 19:57:48 +01:00
|
|
|
, BinOp Add (snd bounds) $ BinOp Sub (snd dim) (snd rOuter) )
|
2020-07-03 02:50:26 +02:00
|
|
|
undotted = Range e' NonIndexed $
|
|
|
|
|
endianCondRange dim rangeLeft rangeRight
|
|
|
|
|
convertSubExpr scopes (Range (Dot e x) mode (baseO, lenO)) =
|
|
|
|
|
if isntStruct subExprType then
|
|
|
|
|
fallbackType scopes orig'
|
|
|
|
|
else if structIsntReady subExprType then
|
2020-07-24 02:23:40 +02:00
|
|
|
(replaceInnerTypeRange mode (baseO, lenO) fieldType, orig')
|
2020-07-03 02:50:26 +02:00
|
|
|
else
|
2020-07-24 02:23:40 +02:00
|
|
|
(replaceInnerTypeRange mode (baseO, lenO) fieldType, undotted)
|
2020-07-03 02:50:26 +02:00
|
|
|
where
|
|
|
|
|
(subExprType, e') = convertSubExpr scopes e
|
|
|
|
|
orig' = Range (Dot e' x) mode (baseO, lenO)
|
|
|
|
|
(fieldType, bounds, dims) = lookupFieldInfo subExprType x
|
|
|
|
|
[dim] = dims
|
|
|
|
|
baseLeft = BinOp Sub (fst bounds) $ BinOp Sub (fst dim) baseO
|
|
|
|
|
baseRight = BinOp Add (snd bounds) $ BinOp Sub (snd dim) baseO
|
|
|
|
|
baseDec = baseLeft
|
|
|
|
|
baseInc = case mode of
|
|
|
|
|
IndexedPlus -> BinOp Add (BinOp Sub baseRight lenO) one
|
|
|
|
|
IndexedMinus -> BinOp Sub (BinOp Add baseRight lenO) one
|
|
|
|
|
NonIndexed -> error "invariant violated"
|
|
|
|
|
base = endianCondExpr dim baseDec baseInc
|
|
|
|
|
undotted = Range e' mode (base, lenO)
|
2020-07-12 23:06:27 +02:00
|
|
|
one = RawNum 1
|
2020-07-03 02:50:26 +02:00
|
|
|
convertSubExpr scopes (Range e mode r) =
|
2020-07-24 02:23:40 +02:00
|
|
|
(replaceInnerTypeRange mode r t, Range e' mode r)
|
2020-07-03 02:50:26 +02:00
|
|
|
where (t, e') = convertSubExpr scopes e
|
|
|
|
|
convertSubExpr scopes (Bit (Dot e x) i) =
|
|
|
|
|
if isntStruct subExprType then
|
|
|
|
|
fallbackType scopes orig'
|
|
|
|
|
else if structIsntReady subExprType then
|
|
|
|
|
(dropInnerTypeRange fieldType, orig')
|
|
|
|
|
else
|
|
|
|
|
(dropInnerTypeRange fieldType, Bit e' i')
|
|
|
|
|
where
|
|
|
|
|
(subExprType, e') = convertSubExpr scopes e
|
|
|
|
|
orig' = Bit (Dot e' x) i
|
|
|
|
|
(fieldType, bounds, dims) = lookupFieldInfo subExprType x
|
|
|
|
|
[dim] = dims
|
|
|
|
|
iLeft = BinOp Sub (fst bounds) $ BinOp Sub (fst dim) i
|
|
|
|
|
iRight = BinOp Add (snd bounds) $ BinOp Sub (snd dim) i
|
|
|
|
|
i' = endianCondExpr dim iLeft iRight
|
|
|
|
|
convertSubExpr scopes (Bit e i) =
|
|
|
|
|
if t == unknownType
|
|
|
|
|
then fallbackType scopes $ Bit e' i
|
|
|
|
|
else (dropInnerTypeRange t, Bit e' i)
|
|
|
|
|
where (t, e') = convertSubExpr scopes e
|
|
|
|
|
convertSubExpr scopes (Call e args) =
|
|
|
|
|
(retType, Call e args')
|
|
|
|
|
where
|
|
|
|
|
(retType, _) = fallbackType scopes e
|
|
|
|
|
args' = convertCall scopes e args
|
|
|
|
|
convertSubExpr scopes (Cast (Left t) e) =
|
|
|
|
|
(t, Cast (Left t) e')
|
|
|
|
|
where (_, e') = convertSubExpr scopes e
|
|
|
|
|
convertSubExpr scopes (Pattern items) =
|
|
|
|
|
if all (== "") $ map fst items'
|
|
|
|
|
then (unknownType, Concat $ map snd items')
|
|
|
|
|
else (unknownType, Pattern items')
|
|
|
|
|
where
|
|
|
|
|
items' = map mapItem items
|
|
|
|
|
mapItem (x, e) = (x, e')
|
|
|
|
|
where (_, e') = convertSubExpr scopes e
|
|
|
|
|
convertSubExpr scopes (Mux a b c) =
|
|
|
|
|
(t, Mux a' b' c')
|
|
|
|
|
where
|
|
|
|
|
(_, a') = convertSubExpr scopes a
|
|
|
|
|
(t, b') = convertSubExpr scopes b
|
|
|
|
|
(_, c') = convertSubExpr scopes c
|
|
|
|
|
convertSubExpr scopes other =
|
|
|
|
|
fallbackType scopes other
|
|
|
|
|
|
|
|
|
|
-- get the fields and type function of a struct or union
|
|
|
|
|
getFields :: Type -> Maybe [Field]
|
|
|
|
|
getFields (Struct _ fields []) = Just fields
|
|
|
|
|
getFields (Union _ fields []) = Just fields
|
|
|
|
|
getFields _ = Nothing
|
|
|
|
|
|
|
|
|
|
isntStruct :: Type -> Bool
|
|
|
|
|
isntStruct = (== Nothing) . getFields
|
|
|
|
|
|
|
|
|
|
-- get the field type, flattended bounds, and original type dimensions
|
|
|
|
|
lookupFieldInfo :: Type -> Identifier -> (Type, Range, [Range])
|
|
|
|
|
lookupFieldInfo struct fieldName =
|
|
|
|
|
if maybeFieldType == Nothing
|
|
|
|
|
then error $ "field '" ++ fieldName ++ "' not found in: " ++ show struct
|
|
|
|
|
else (fieldType, bounds, dims)
|
|
|
|
|
where
|
|
|
|
|
Just fields = getFields struct
|
|
|
|
|
maybeFieldType = lookup fieldName $ map swap fields
|
|
|
|
|
Just fieldType = maybeFieldType
|
|
|
|
|
dims = snd $ typeRanges fieldType
|
|
|
|
|
Just (_, unstructRanges) = convertStruct struct
|
|
|
|
|
Just bounds = Map.lookup fieldName unstructRanges
|
2020-02-17 19:57:48 +01:00
|
|
|
|
2019-04-22 19:58:14 +02:00
|
|
|
-- attempts to convert based on the assignment-like contexts of TF arguments
|
2020-07-03 02:50:26 +02:00
|
|
|
convertCall :: Scopes Type -> Expr -> Args -> Args
|
|
|
|
|
convertCall scopes fn (Args pnArgs kwArgs) =
|
|
|
|
|
case exprToLHS fn of
|
|
|
|
|
Just fnLHS ->
|
|
|
|
|
Args (map snd pnArgs') kwArgs'
|
|
|
|
|
where
|
|
|
|
|
pnArgs' = map (convertArg fnLHS) $ zip idxs pnArgs
|
|
|
|
|
kwArgs' = map (convertArg fnLHS) kwArgs
|
2019-10-19 22:22:39 +02:00
|
|
|
_ -> Args pnArgs kwArgs
|
2019-04-22 19:58:14 +02:00
|
|
|
where
|
|
|
|
|
idxs = map show ([0..] :: [Int])
|
2020-07-03 02:50:26 +02:00
|
|
|
convertArg :: LHS -> (Identifier, Expr) -> (Identifier, Expr)
|
|
|
|
|
convertArg lhs (x, e) =
|
|
|
|
|
(x, e')
|
2019-04-22 19:58:14 +02:00
|
|
|
where
|
2020-07-15 06:22:41 +02:00
|
|
|
details = lookupElem scopes $ LHSDot lhs x
|
2020-07-03 02:50:26 +02:00
|
|
|
typ = maybe unknownType thd3 details
|
|
|
|
|
thd3 (_, _, c) = c
|
|
|
|
|
(_, e') = convertSubExpr scopes $ convertExpr typ e
|