Commit e9f96963 by Zachary Snow

extend typeof operator support

parent 5eaecc66
...@@ -40,6 +40,7 @@ module Convert.Scoper ...@@ -40,6 +40,7 @@ module Convert.Scoper
, withinProcedure , withinProcedure
, withinProcedureM , withinProcedureM
, scopeModuleItemT , scopeModuleItemT
, Replacements
) where ) where
import Control.Monad.State.Strict import Control.Monad.State.Strict
......
...@@ -3,6 +3,14 @@ ...@@ -3,6 +3,14 @@
- Author: Zachary Snow <zach@zachjs.com> - Author: Zachary Snow <zach@zachjs.com>
- -
- Conversion for the `type` operator - Conversion for the `type` operator
-
- This conversion is responsible for explicit type resolution throughout sv2v.
- It uses Scoper to resolve hierarchical expressions in a scope-aware manner.
-
- Some other conversions, such as the dimension query and streaming
- concatenation conversions, defer the resolution of type information to this
- conversion pass by producing nodes with the `type` operator during
- elaboration.
-} -}
module Convert.TypeOf (convert) where module Convert.TypeOf (convert) where
...@@ -19,9 +27,15 @@ convert :: [AST] -> [AST] ...@@ -19,9 +27,15 @@ convert :: [AST] -> [AST]
convert = map $ traverseDescriptions $ partScoper convert = map $ traverseDescriptions $ partScoper
traverseDeclM traverseModuleItemM traverseGenItemM traverseStmtM traverseDeclM traverseModuleItemM traverseGenItemM traverseStmtM
-- internal representation of a fully implicit type
pattern UnknownType :: Type pattern UnknownType :: Type
pattern UnknownType = Implicit Unspecified [] pattern UnknownType = Implicit Unspecified []
-- single bit 4-state `logic` type
pattern UnitType :: Type
pattern UnitType = IntegerVector TLogic Unspecified []
-- insert the given declaration into the scope, and convert an TypeOfs within
traverseDeclM :: Decl -> Scoper Type Decl traverseDeclM :: Decl -> Scoper Type Decl
traverseDeclM decl = do traverseDeclM decl = do
item <- traverseModuleItemM (MIPackageItem $ Decl decl) item <- traverseModuleItemM (MIPackageItem $ Decl decl)
...@@ -29,7 +43,7 @@ traverseDeclM decl = do ...@@ -29,7 +43,7 @@ traverseDeclM decl = do
case decl' of case decl' of
Variable Local UnknownType ident [] Nil -> do Variable Local UnknownType ident [] Nil -> do
-- functions with no return type implicitly return a single bit -- functions with no return type implicitly return a single bit
insertElem ident $ IntegerVector TLogic Unspecified [] insertElem ident UnitType
return decl' return decl'
Variable d t ident a e -> do Variable d t ident a e -> do
let t' = injectRanges t a let t' = injectRanges t a
...@@ -46,6 +60,7 @@ traverseDeclM decl = do ...@@ -46,6 +60,7 @@ traverseDeclM decl = do
ParamType{} -> return decl' ParamType{} -> return decl'
CommentDecl{} -> return decl' CommentDecl{} -> return decl'
-- convert TypeOf in a ModuleItem
traverseModuleItemM :: ModuleItem -> Scoper Type ModuleItem traverseModuleItemM :: ModuleItem -> Scoper Type ModuleItem
traverseModuleItemM (Genvar x) = do traverseModuleItemM (Genvar x) = do
insertElem x $ IntegerAtom TInteger Unspecified insertElem x $ IntegerAtom TInteger Unspecified
...@@ -53,12 +68,15 @@ traverseModuleItemM (Genvar x) = do ...@@ -53,12 +68,15 @@ traverseModuleItemM (Genvar x) = do
traverseModuleItemM item = traverseModuleItemM item =
traverseTypesM (traverseNestedTypesM traverseTypeM) item traverseTypesM (traverseNestedTypesM traverseTypeM) item
-- convert TypeOf in a GenItem
traverseGenItemM :: GenItem -> Scoper Type GenItem traverseGenItemM :: GenItem -> Scoper Type GenItem
traverseGenItemM = traverseGenItemExprsM traverseExprM traverseGenItemM = traverseGenItemExprsM traverseExprM
-- convert TypeOf in a Stmt
traverseStmtM :: Stmt -> Scoper Type Stmt traverseStmtM :: Stmt -> Scoper Type Stmt
traverseStmtM = traverseStmtExprsM traverseExprM traverseStmtM = traverseStmtExprsM traverseExprM
-- convert TypeOf in a Expr
traverseExprM :: Expr -> Scoper Type Expr traverseExprM :: Expr -> Scoper Type Expr
traverseExprM = traverseNestedExprsM $ traverseExprTypesM $ traverseExprM = traverseNestedExprsM $ traverseExprTypesM $
traverseNestedTypesM traverseTypeM traverseNestedTypesM traverseTypeM
...@@ -67,6 +85,8 @@ traverseTypeM :: Type -> Scoper Type Type ...@@ -67,6 +85,8 @@ traverseTypeM :: Type -> Scoper Type Type
traverseTypeM (TypeOf expr) = typeof expr traverseTypeM (TypeOf expr) = typeof expr
traverseTypeM other = return other traverseTypeM other = return other
-- attempts to find the given (potentially hierarchical or generate-scoped)
-- expression in the available scope information
lookupTypeOf :: Expr -> Scoper Type Type lookupTypeOf :: Expr -> Scoper Type Type
lookupTypeOf expr = do lookupTypeOf expr = do
details <- lookupElemM expr details <- lookupElemM expr
...@@ -75,15 +95,18 @@ lookupTypeOf expr = do ...@@ -75,15 +95,18 @@ lookupTypeOf expr = do
Just (_, replacements, typ) -> Just (_, replacements, typ) ->
return $ if Map.null replacements return $ if Map.null replacements
then typ then typ
else rewriteType typ else rewriteType replacements typ
where where
rewriteType = traverseNestedTypes $ traverseTypeExprs $ rewriteType :: Replacements -> Type -> Type
traverseNestedExprs replace rewriteType replacements = traverseNestedTypes $ traverseTypeExprs $
replace :: Expr -> Expr traverseNestedExprs (replace replacements)
replace (Ident x) = replace :: Replacements -> Expr -> Expr
replace replacements (Ident x) =
Map.findWithDefault (Ident x) x replacements Map.findWithDefault (Ident x) x replacements
replace other = other replace _ other = other
-- determines the type of an expression based on the available scope information
-- according the semantics defined in IEEE 1800-2017, especially Section 11.6
typeof :: Expr -> Scoper Type Type typeof :: Expr -> Scoper Type Type
typeof (Number n) = typeof (Number n) =
return $ IntegerVector TLogic sg [r] return $ IntegerVector TLogic sg [r]
...@@ -91,14 +114,7 @@ typeof (Number n) = ...@@ -91,14 +114,7 @@ typeof (Number n) =
r = (RawNum $ size - 1, RawNum 0) r = (RawNum $ size - 1, RawNum 0)
size = numberBitLength n size = numberBitLength n
sg = if numberIsSigned n then Signed else Unspecified sg = if numberIsSigned n then Signed else Unspecified
typeof (Call (Ident "$unsigned") (Args [e] [])) = typeof (Call (Ident x) args) = typeofCall x args
typeof e
typeof (Call (Ident "$signed") (Args [e] [])) =
typeof e
typeof (Call (Ident "$clog2") (Args [_] [])) =
return $ IntegerAtom TInteger Unspecified
typeof (Call (Ident x) _) =
typeof $ Ident x
typeof (orig @ (Bit e _)) = do typeof (orig @ (Bit e _)) = do
t <- typeof e t <- typeof e
case t of case t of
...@@ -120,10 +136,8 @@ typeof (orig @ (Range e mode r)) = do ...@@ -120,10 +136,8 @@ typeof (orig @ (Range e mode r)) = do
typeof (orig @ (Dot e x)) = do typeof (orig @ (Dot e x)) = do
t <- typeof e t <- typeof e
case t of case t of
Struct _ fields [] -> Struct _ fields [] -> return $ fieldsType fields
return $ fieldsType fields Union _ fields [] -> return $ fieldsType fields
Union _ fields [] ->
return $ fieldsType fields
_ -> lookupTypeOf orig _ -> lookupTypeOf orig
where where
fieldsType :: [Field] -> Type fieldsType :: [Field] -> Type
...@@ -132,23 +146,8 @@ typeof (orig @ (Dot e x)) = do ...@@ -132,23 +146,8 @@ typeof (orig @ (Dot e x)) = do
Just typ -> typ Just typ -> typ
Nothing -> TypeOf orig Nothing -> TypeOf orig
typeof (Cast (Right s) _) = return $ typeOfSize s typeof (Cast (Right s) _) = return $ typeOfSize s
typeof (UniOp UniSub e ) = typeof e typeof (UniOp op expr) = typeofUniOp op expr
typeof (UniOp BitNot e ) = typeof e typeof (BinOp op a b) = typeofBinOp op a b
typeof (UniOp LogNot _ ) = return $ IntegerVector TLogic Unspecified []
typeof (BinOp Pow e _) = typeof e
typeof (BinOp ShiftL e _) = typeof e
typeof (BinOp ShiftR e _) = typeof e
typeof (BinOp ShiftAL e _) = typeof e
typeof (BinOp ShiftAR e _) = typeof e
typeof (BinOp Add a b) = largerSizeType a b
typeof (BinOp Sub a b) = largerSizeType a b
typeof (BinOp Mul a b) = largerSizeType a b
typeof (BinOp Div a b) = largerSizeType a b
typeof (BinOp Mod a b) = largerSizeType a b
typeof (BinOp BitAnd a b) = largerSizeType a b
typeof (BinOp BitXor a b) = largerSizeType a b
typeof (BinOp BitXnor a b) = largerSizeType a b
typeof (BinOp BitOr a b) = largerSizeType a b
typeof (Mux _ a b) = largerSizeType a b typeof (Mux _ a b) = largerSizeType a b
typeof (Concat exprs) = return $ typeOfSize $ concatSize exprs typeof (Concat exprs) = return $ typeOfSize $ concatSize exprs
typeof (Repeat reps exprs) = return $ typeOfSize size typeof (Repeat reps exprs) = return $ typeOfSize size
...@@ -158,12 +157,65 @@ typeof (String str) = ...@@ -158,12 +157,65 @@ typeof (String str) =
where where
r = (RawNum $ len - 1, RawNum 0) r = (RawNum $ len - 1, RawNum 0)
len = if null str then 1 else 8 * unescapedLength str len = if null str then 1 else 8 * unescapedLength str
unescapedLength :: String -> Integer
unescapedLength [] = 0
unescapedLength ('\\' : _ : rest) = 1 + unescapedLength rest
unescapedLength (_ : rest) = 1 + unescapedLength rest
typeof other = lookupTypeOf other typeof other = lookupTypeOf other
-- length of a string literal in characters
unescapedLength :: String -> Integer
unescapedLength [] = 0
unescapedLength ('\\' : _ : rest) = 1 + unescapedLength rest
unescapedLength (_ : rest) = 1 + unescapedLength rest
-- type of a standard (non-member) function call
typeofCall :: String -> Args -> Scoper Type Type
typeofCall "$unsigned" (Args [e] []) = typeof e
typeofCall "$signed" (Args [e] []) = typeof e
typeofCall "$clog2" (Args [_] []) =
return $ IntegerAtom TInteger Unspecified
typeofCall fnName _ = typeof $ Ident fnName
-- type of a unary operator expression
typeofUniOp :: UniOp -> Expr -> Scoper Type Type
typeofUniOp UniAdd e = typeof e
typeofUniOp UniSub e = typeof e
typeofUniOp BitNot e = typeof e
typeofUniOp _ _ =
-- unary reductions and logical negation
return UnitType
-- type of a binary operator expression (Section 11.6.1)
typeofBinOp :: BinOp -> Expr -> Expr -> Scoper Type Type
typeofBinOp op a b =
case op of
LogAnd -> unitType
LogOr -> unitType
LogImp -> unitType
LogEq -> unitType
Eq -> unitType
Ne -> unitType
TEq -> unitType
TNe -> unitType
WEq -> unitType
WNe -> unitType
Lt -> unitType
Le -> unitType
Gt -> unitType
Ge -> unitType
Pow -> typeof a
ShiftL -> typeof a
ShiftR -> typeof a
ShiftAL -> typeof a
ShiftAR -> typeof a
Add -> largerSizeType a b
Sub -> largerSizeType a b
Mul -> largerSizeType a b
Div -> largerSizeType a b
Mod -> largerSizeType a b
BitAnd -> largerSizeType a b
BitXor -> largerSizeType a b
BitXnor -> largerSizeType a b
BitOr -> largerSizeType a b
where unitType = return UnitType
-- produces a type large enough to hold either expression -- produces a type large enough to hold either expression
largerSizeType :: Expr -> Expr -> Scoper Type Type largerSizeType :: Expr -> Expr -> Scoper Type Type
largerSizeType a (Number (Based 1 _ _ _ _)) = typeof a largerSizeType a (Number (Based 1 _ _ _ _)) = typeof a
......
`define TEST(expr) \
$display(`"expr = %b; $bits(expr) = %0d`", (expr), $bits(expr));
module top;
initial begin
`TEST(4'b1011)
`TEST(5'b01110)
`TEST(! 3'b101)
`TEST(~ 3'b101)
`TEST(+ 3'b101)
`TEST(- 3'b101)
`TEST(& 3'b101)
`TEST(~& 3'b101)
`TEST(| 3'b101)
`TEST(~| 3'b101)
`TEST(^ 3'b101)
`TEST(~^ 3'b101)
`TEST(4'b1011 && 5'b01110)
`TEST(4'b1011 || 5'b01110)
`TEST(4'b1011 & 5'b01110)
`TEST(4'b1011 ^ 5'b01110)
`TEST(4'b1011 ~^ 5'b01110)
`TEST(4'b1011 | 5'b01110)
`TEST(4'b1011 << 5'b01110)
`TEST(4'b1011 >> 5'b01110)
`TEST(4'b1011 <<< 5'b01110)
`TEST(4'b1011 >>> 5'b01110)
`TEST(4'b1011 == 5'b01110)
`TEST(4'b1011 != 5'b01110)
`TEST(4'b1011 === 5'b01110)
`TEST(4'b1011 !== 5'b01110)
`TEST(4'b1011 < 5'b01110)
`TEST(4'b1011 <= 5'b01110)
`TEST(4'b1011 > 5'b01110)
`TEST(4'b1011 >= 5'b01110)
// TODO: iverilog incorrectly handles width of these
// `TEST(4'b1011 * 5'b01110)
// `TEST(4'b1011 / 5'b01110)
// `TEST(4'b1011 % 5'b01110)
// `TEST(4'b1011 + 5'b01110)
// `TEST(4'b1011 - 5'b01110)
// `TEST(4'b1011 ** 5'b01110)
// TODO: not yet supported by iverilog
// `TEST(4'b1011 -> 5'b01110)
// `TEST(4'b1011 <-> 5'b01110)
// `TEST(4'b1011 ==? 5'b01110)
// `TEST(4'b1011 !=? 5'b01110)
end
endmodule
`include "typeof_op.sv"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment