2021-02-11 22:50:13 +01:00
|
|
|
{-# LANGUAGE TupleSections #-}
|
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)
|
2021-06-20 21:30:21 +02:00
|
|
|
import Data.Either (isLeft)
|
2021-07-08 19:58:02 +02:00
|
|
|
import Data.List (elemIndex, find, partition, (\\))
|
2021-06-20 21:30:21 +02:00
|
|
|
import Data.Maybe (fromJust)
|
2019-03-06 06:51:09 +01:00
|
|
|
import Data.Tuple (swap)
|
|
|
|
|
|
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
|
|
|
|
|
|
2021-07-08 19:58:02 +02:00
|
|
|
type StructInfo = (Type, [(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-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 =
|
2021-03-09 20:18:37 +01:00
|
|
|
if null ranges
|
|
|
|
|
then (zero, zero)
|
|
|
|
|
else let [range] = ranges in range
|
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
|
2021-07-08 19:58:02 +02:00
|
|
|
unstructFields = 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
|
2021-07-01 01:13:44 +02:00
|
|
|
Nothing -> traverseSinglyNestedTypes convertType 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
|
2021-07-02 23:59:21 +02:00
|
|
|
traverseDeclM decl @ Net{} =
|
|
|
|
|
traverseNetAsVarM traverseDeclM decl
|
2020-07-03 02:50:26 +02:00
|
|
|
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) $
|
2021-02-22 20:13:37 +01:00
|
|
|
scopeType (tf $ a ++ rs) >>= insertElem x
|
2020-07-03 02:50:26 +02:00
|
|
|
let e' = convertExpr t e
|
2021-07-01 01:13:44 +02:00
|
|
|
let t' = convertType t
|
|
|
|
|
return $ Variable d t' x a e'
|
2019-09-07 04:29:14 +02:00
|
|
|
Param s t x e -> do
|
2021-02-22 20:13:37 +01:00
|
|
|
scopeType t >>= insertElem x
|
2020-07-03 02:50:26 +02:00
|
|
|
let e' = convertExpr t e
|
2021-07-01 01:13:44 +02:00
|
|
|
let t' = convertType t
|
|
|
|
|
return $ Param s t' x e'
|
2021-07-02 23:59:21 +02:00
|
|
|
_ -> return decl
|
2020-07-03 02:50:26 +02:00
|
|
|
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
|
2021-02-19 20:50:05 +01:00
|
|
|
isRangeable TypeOf{} = 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
|
2021-07-21 20:31:43 +02:00
|
|
|
traverseExprM = embedScopes convertSubExpr >=> return . snd
|
2020-07-03 02:50:26 +02:00
|
|
|
|
|
|
|
|
traverseLHSM :: LHS -> Scoper Type LHS
|
2021-02-11 22:50:13 +01:00
|
|
|
traverseLHSM = convertLHS >=> return . snd
|
2020-07-03 02:50:26 +02:00
|
|
|
|
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
|
2021-02-11 22:50:13 +01: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
|
2021-02-11 22:50:13 +01:00
|
|
|
(_, []) -> UnknownType
|
2020-07-24 02:23:40 +02:00
|
|
|
(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
|
|
|
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')
|
|
|
|
|
|
|
|
|
|
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) =
|
2021-07-08 19:58:02 +02:00
|
|
|
if not (null extraNames) then
|
2020-07-03 02:50:26 +02:00
|
|
|
error $ "pattern " ++ show (Pattern itemsOrig) ++
|
2021-07-08 19:58:02 +02:00
|
|
|
" has extra named fields " ++ show extraNames ++
|
2021-03-09 20:18:37 +01:00
|
|
|
" that are not in " ++ show struct
|
2020-07-03 02:50:26 +02:00
|
|
|
else if structIsntReady struct then
|
|
|
|
|
Pattern items
|
|
|
|
|
else
|
2021-07-08 19:58:02 +02:00
|
|
|
Concat $ zipWith (Cast . Left) fieldTypes (map snd items)
|
2020-07-03 02:50:26 +02:00
|
|
|
where
|
2021-07-08 19:58:02 +02:00
|
|
|
(fieldTypes, fieldNames) = unzip fields
|
2020-07-03 02:50:26 +02:00
|
|
|
|
|
|
|
|
itemsNamed =
|
|
|
|
|
-- patterns either use positions based or name/type/default
|
2021-06-20 21:30:21 +02:00
|
|
|
if all ((/= Right Nil) . fst) itemsOrig then
|
2020-07-03 02:50:26 +02:00
|
|
|
itemsOrig
|
|
|
|
|
-- position-based patterns should cover every field
|
|
|
|
|
else if length itemsOrig /= length fields then
|
|
|
|
|
error $ "struct pattern " ++ show (Pattern itemsOrig) ++
|
2021-03-09 20:18:37 +01:00
|
|
|
" doesn't have the same number of items as " ++ show struct
|
2020-07-03 02:50:26 +02:00
|
|
|
-- 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
|
2021-06-20 21:30:21 +02:00
|
|
|
zip (map (Right . Ident) fieldNames) (map snd itemsOrig)
|
|
|
|
|
(typedItems, untypedItems) =
|
2021-07-08 19:58:02 +02:00
|
|
|
partition (isLeft . fst) $ reverse itemsNamed
|
2021-06-20 21:30:21 +02:00
|
|
|
(numberedItems, namedItems) =
|
|
|
|
|
partition (isNumbered . fst) untypedItems
|
|
|
|
|
|
|
|
|
|
isNumbered :: TypeOrExpr -> Bool
|
|
|
|
|
isNumbered (Right (Number n)) =
|
|
|
|
|
if maybeIndex == Nothing
|
|
|
|
|
then error msgNonInteger
|
2021-08-08 05:11:35 +02:00
|
|
|
else 0 <= index && index < length fieldNames
|
|
|
|
|
|| error msgOutOfBounds
|
2021-06-20 21:30:21 +02:00
|
|
|
where
|
|
|
|
|
maybeIndex = fmap fromIntegral $ numberToInteger n
|
|
|
|
|
Just index = maybeIndex
|
|
|
|
|
msgNonInteger = "pattern index " ++ show (Number n)
|
|
|
|
|
++ " is not an integer"
|
|
|
|
|
msgOutOfBounds = "pattern index " ++ show index
|
|
|
|
|
++ " is out of bounds for " ++ show struct
|
|
|
|
|
isNumbered _ = False
|
2020-07-03 02:50:26 +02:00
|
|
|
|
2021-07-08 19:58:02 +02:00
|
|
|
extraNames = map (getName . right . fst) namedItems \\ fieldNames
|
2021-06-20 21:30:21 +02:00
|
|
|
right = \(Right x) -> x
|
|
|
|
|
getName :: Expr -> Identifier
|
|
|
|
|
getName (Ident x) = x
|
|
|
|
|
getName e = error $ "invalid pattern key " ++ show e
|
|
|
|
|
++ " is not a type, field name, or index"
|
|
|
|
|
|
|
|
|
|
items = zip
|
|
|
|
|
(map (Right . Ident) fieldNames)
|
|
|
|
|
(map resolveField fieldNames)
|
2020-07-03 02:50:26 +02:00
|
|
|
resolveField :: Identifier -> Expr
|
|
|
|
|
resolveField fieldName =
|
|
|
|
|
convertExpr fieldType $
|
|
|
|
|
-- look up by name
|
2021-06-20 21:30:21 +02:00
|
|
|
if valueByName /= Nothing then
|
|
|
|
|
fromJust valueByName
|
2020-07-03 02:50:26 +02:00
|
|
|
-- recurse for substructures
|
|
|
|
|
else if isStruct fieldType then
|
2021-06-20 21:30:21 +02:00
|
|
|
Pattern typedItems
|
2020-07-03 02:50:26 +02:00
|
|
|
-- look up by field type
|
2021-06-20 21:30:21 +02:00
|
|
|
else if valueByType /= Nothing then
|
|
|
|
|
fromJust valueByType
|
2020-07-03 02:50:26 +02:00
|
|
|
-- fall back on the default value
|
2021-06-20 21:30:21 +02:00
|
|
|
else if valueDefault /= Nothing then
|
|
|
|
|
fromJust valueDefault
|
|
|
|
|
else if valueByIndex /= Nothing then
|
|
|
|
|
fromJust valueByIndex
|
2020-07-03 02:50:26 +02:00
|
|
|
else
|
2021-03-09 20:18:37 +01:00
|
|
|
error $ "couldn't find field '" ++ fieldName ++
|
|
|
|
|
"' from struct definition " ++ show struct ++
|
|
|
|
|
" in struct pattern " ++ show (Pattern itemsOrig)
|
2019-11-20 05:15:22 +01:00
|
|
|
where
|
2021-07-08 19:58:02 +02:00
|
|
|
valueByName = lookup (Right $ Ident fieldName) namedItems
|
|
|
|
|
valueByType = lookup (Left fieldType) typedItems
|
|
|
|
|
valueDefault = lookup (Left UnknownType) typedItems
|
2021-06-20 21:30:21 +02:00
|
|
|
valueByIndex = fmap snd $ find (indexCheck . fst) numberedItems
|
|
|
|
|
|
2021-07-08 19:58:02 +02:00
|
|
|
fieldType = fst $ fields !! fieldIndex
|
2021-06-20 21:30:21 +02:00
|
|
|
Just fieldIndex = elemIndex fieldName fieldNames
|
|
|
|
|
|
2020-07-03 02:50:26 +02:00
|
|
|
isStruct :: Type -> Bool
|
2021-06-20 21:30:21 +02:00
|
|
|
isStruct Struct{} = True
|
2020-07-03 02:50:26 +02:00
|
|
|
isStruct _ = False
|
|
|
|
|
|
2021-06-20 21:30:21 +02:00
|
|
|
indexCheck :: TypeOrExpr -> Bool
|
|
|
|
|
indexCheck item =
|
|
|
|
|
fromIntegral value == fieldIndex
|
|
|
|
|
where
|
|
|
|
|
Just value = numberToInteger n
|
|
|
|
|
Right (Number n) = item
|
|
|
|
|
|
2021-07-21 20:31:43 +02:00
|
|
|
convertExpr _ (Cast (Left t) expr) =
|
|
|
|
|
Cast (Left t') $ convertExpr t expr
|
|
|
|
|
where t' = convertType t
|
2021-07-19 17:42:36 +02:00
|
|
|
|
2021-07-21 20:31:43 +02:00
|
|
|
convertExpr (Implicit _ []) expr =
|
|
|
|
|
traverseSinglyNestedExprs (convertExpr UnknownType) expr
|
2020-07-22 02:05:27 +02:00
|
|
|
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?
|
2021-06-20 21:30:21 +02:00
|
|
|
convertExpr t (orig @ (Pattern [(Left UnknownType, expr)])) =
|
2020-07-22 02:05:27 +02:00
|
|
|
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) =
|
2021-06-20 21:30:21 +02:00
|
|
|
if all (== Right Nil) names
|
2020-07-22 02:05:27 +02:00
|
|
|
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
|
|
|
|
|
|
2021-07-21 20:31:43 +02:00
|
|
|
convertExpr _ expr =
|
|
|
|
|
traverseSinglyNestedExprs (convertExpr UnknownType) expr
|
2020-07-03 02:50:26 +02:00
|
|
|
|
|
|
|
|
fallbackType :: Scopes Type -> Expr -> (Type, Expr)
|
|
|
|
|
fallbackType scopes e =
|
2021-02-11 22:50:13 +01:00
|
|
|
(t, e)
|
|
|
|
|
where
|
|
|
|
|
t = case lookupElem scopes e of
|
|
|
|
|
Nothing -> UnknownType
|
|
|
|
|
Just (_, _, typ) -> typ
|
2020-07-03 02:50:26 +02:00
|
|
|
|
|
|
|
|
-- 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
|
2021-03-09 20:18:37 +01:00
|
|
|
let Just l' = exprToLHS e'
|
|
|
|
|
return (t, l')
|
2020-07-03 02:50:26 +02:00
|
|
|
|
|
|
|
|
-- 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
|
2021-05-10 01:23:00 +02:00
|
|
|
(UnknownType, orig')
|
2020-07-03 02:50:26 +02:00
|
|
|
else if structIsntReady subExprType then
|
2021-02-11 22:50:13 +01:00
|
|
|
(replaceInnerTypeRange NonIndexed rOuter' fieldType, orig')
|
2020-07-03 02:50:26 +02:00
|
|
|
else
|
2021-02-11 22:50:13 +01:00
|
|
|
(replaceInnerTypeRange NonIndexed rOuter' fieldType, undotted)
|
2020-07-03 02:50:26 +02:00
|
|
|
where
|
2021-02-11 22:50:13 +01:00
|
|
|
(roLeft, roRight) = rOuter
|
2020-07-03 02:50:26 +02:00
|
|
|
(subExprType, e') = convertSubExpr scopes e
|
2021-02-11 22:50:13 +01:00
|
|
|
(_, roLeft') = convertSubExpr scopes roLeft
|
|
|
|
|
(_, roRight') = convertSubExpr scopes roRight
|
|
|
|
|
rOuter' = (roLeft', roRight')
|
|
|
|
|
orig' = Range (Dot e' x) NonIndexed rOuter'
|
2020-07-03 02:50:26 +02:00
|
|
|
(fieldType, bounds, dims) = lookupFieldInfo subExprType x
|
|
|
|
|
[dim] = dims
|
2021-02-11 22:50:13 +01:00
|
|
|
rangeLeft = ( BinOp Sub (fst bounds) $ BinOp Sub (fst dim) roLeft'
|
|
|
|
|
, BinOp Sub (fst bounds) $ BinOp Sub (fst dim) roRight' )
|
|
|
|
|
rangeRight =( BinOp Add (snd bounds) $ BinOp Sub (snd dim) roLeft'
|
|
|
|
|
, BinOp Add (snd bounds) $ BinOp Sub (snd dim) roRight' )
|
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
|
2021-05-10 01:23:00 +02:00
|
|
|
(UnknownType, orig')
|
2020-07-03 02:50:26 +02:00
|
|
|
else if structIsntReady subExprType then
|
2021-02-11 22:50:13 +01:00
|
|
|
(replaceInnerTypeRange mode (baseO', lenO') fieldType, orig')
|
2020-07-03 02:50:26 +02:00
|
|
|
else
|
2021-02-11 22:50:13 +01:00
|
|
|
(replaceInnerTypeRange mode (baseO', lenO') fieldType, undotted)
|
2020-07-03 02:50:26 +02:00
|
|
|
where
|
|
|
|
|
(subExprType, e') = convertSubExpr scopes e
|
2021-02-11 22:50:13 +01:00
|
|
|
(_, baseO') = convertSubExpr scopes baseO
|
|
|
|
|
(_, lenO') = convertSubExpr scopes lenO
|
|
|
|
|
orig' = Range (Dot e' x) mode (baseO', lenO')
|
2020-07-03 02:50:26 +02:00
|
|
|
(fieldType, bounds, dims) = lookupFieldInfo subExprType x
|
|
|
|
|
[dim] = dims
|
2021-02-11 22:50:13 +01:00
|
|
|
baseLeft = BinOp Sub (fst bounds) $ BinOp Sub (fst dim) baseO'
|
|
|
|
|
baseRight = BinOp Add (snd bounds) $ BinOp Sub (snd dim) baseO'
|
2020-07-03 02:50:26 +02:00
|
|
|
baseDec = baseLeft
|
2021-03-09 20:18:37 +01:00
|
|
|
baseInc = if mode == IndexedPlus
|
|
|
|
|
then BinOp Add (BinOp Sub baseRight lenO') one
|
|
|
|
|
else BinOp Sub (BinOp Add baseRight lenO') one
|
2020-07-03 02:50:26 +02:00
|
|
|
base = endianCondExpr dim baseDec baseInc
|
2021-02-11 22:50:13 +01:00
|
|
|
undotted = Range e' mode (base, lenO')
|
2020-07-12 23:06:27 +02:00
|
|
|
one = RawNum 1
|
2021-02-11 22:50:13 +01:00
|
|
|
convertSubExpr scopes (Range e mode (left, right)) =
|
|
|
|
|
(replaceInnerTypeRange mode r' t, Range e' mode r')
|
|
|
|
|
where
|
|
|
|
|
(t, e') = convertSubExpr scopes e
|
|
|
|
|
(_, left') = convertSubExpr scopes left
|
|
|
|
|
(_, right') = convertSubExpr scopes right
|
|
|
|
|
r' = (left', right')
|
2020-07-03 02:50:26 +02:00
|
|
|
convertSubExpr scopes (Bit (Dot e x) i) =
|
|
|
|
|
if isntStruct subExprType then
|
2021-05-10 01:23:00 +02:00
|
|
|
(dropInnerTypeRange backupType, orig')
|
2020-07-03 02:50:26 +02:00
|
|
|
else if structIsntReady subExprType then
|
|
|
|
|
(dropInnerTypeRange fieldType, orig')
|
|
|
|
|
else
|
2021-02-11 22:50:13 +01:00
|
|
|
(dropInnerTypeRange fieldType, Bit e' iFlat)
|
2020-07-03 02:50:26 +02:00
|
|
|
where
|
|
|
|
|
(subExprType, e') = convertSubExpr scopes e
|
2021-02-11 22:50:13 +01:00
|
|
|
(_, i') = convertSubExpr scopes i
|
2021-05-10 01:23:00 +02:00
|
|
|
(backupType, _) = fallbackType scopes $ Dot e' x
|
2021-02-11 22:50:13 +01:00
|
|
|
orig' = Bit (Dot e' x) i'
|
2020-07-03 02:50:26 +02:00
|
|
|
(fieldType, bounds, dims) = lookupFieldInfo subExprType x
|
|
|
|
|
[dim] = dims
|
2021-02-11 22:50:13 +01:00
|
|
|
left = BinOp Sub (fst bounds) $ BinOp Sub (fst dim) i'
|
|
|
|
|
right = BinOp Add (snd bounds) $ BinOp Sub (snd dim) i'
|
|
|
|
|
iFlat = endianCondExpr dim left right
|
2020-07-03 02:50:26 +02:00
|
|
|
convertSubExpr scopes (Bit e i) =
|
2021-02-11 22:50:13 +01:00
|
|
|
if t == UnknownType
|
2021-05-10 01:23:00 +02:00
|
|
|
then (UnknownType, Bit e' i')
|
2021-02-11 22:50:13 +01:00
|
|
|
else (dropInnerTypeRange t, Bit e' i')
|
|
|
|
|
where
|
|
|
|
|
(t, e') = convertSubExpr scopes e
|
|
|
|
|
(_, i') = convertSubExpr scopes i
|
2020-07-03 02:50:26 +02:00
|
|
|
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) =
|
2021-06-20 21:30:21 +02:00
|
|
|
if all (== Right Nil) $ map fst items'
|
2021-02-11 22:50:13 +01:00
|
|
|
then (UnknownType, Concat $ map snd items')
|
|
|
|
|
else (UnknownType, Pattern items')
|
2020-07-03 02:50:26 +02:00
|
|
|
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
|
2021-02-11 22:50:13 +01:00
|
|
|
convertSubExpr scopes (Ident x) =
|
|
|
|
|
fallbackType scopes (Ident x)
|
|
|
|
|
convertSubExpr scopes e =
|
|
|
|
|
(UnknownType, ) $
|
|
|
|
|
traverseExprTypes typeMapper $
|
|
|
|
|
traverseSinglyNestedExprs exprMapper e
|
|
|
|
|
where
|
|
|
|
|
exprMapper = snd . convertSubExpr scopes
|
2021-07-21 20:31:43 +02:00
|
|
|
typeMapper = convertType .
|
|
|
|
|
traverseNestedTypes (traverseTypeExprs exprMapper)
|
2020-07-03 02:50:26 +02:00
|
|
|
|
|
|
|
|
-- 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
|
2021-03-09 20:18:37 +01:00
|
|
|
then error $ "field '" ++ fieldName ++ "' not found in " ++ show struct
|
2020-07-03 02:50:26 +02:00
|
|
|
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
|
2021-07-08 19:58:02 +02:00
|
|
|
Just bounds = 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) =
|
2021-03-09 20:18:37 +01:00
|
|
|
Args (map snd pnArgs') kwArgs'
|
2019-04-22 19:58:14 +02:00
|
|
|
where
|
2021-03-09 20:18:37 +01:00
|
|
|
Just fnLHS = exprToLHS fn
|
|
|
|
|
pnArgs' = map (convertArg fnLHS) $ zip idxs pnArgs
|
|
|
|
|
kwArgs' = map (convertArg fnLHS) kwArgs
|
2019-04-22 19:58:14 +02:00
|
|
|
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
|
2021-02-11 22:50:13 +01:00
|
|
|
typ = maybe UnknownType thd3 details
|
2020-07-03 02:50:26 +02:00
|
|
|
thd3 (_, _, c) = c
|
|
|
|
|
(_, e') = convertSubExpr scopes $ convertExpr typ e
|