mirror of https://github.com/zachjs/sv2v.git
constant folding extensions
- fold string literal comparisons - fold non-decimal bit shifts - fold non-decimal integer comparisons - fold decimal bitwise AND and OR - simplify cast expressions before elaboration - remove duplicate cast expression traversal - flatten concatenated numbers in a single pass
This commit is contained in:
parent
e09aea48e0
commit
96a108ded7
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
* Added elaboration for accesses to fields of struct constants, which can
|
* Added elaboration for accesses to fields of struct constants, which can
|
||||||
substantially improve performance on some designs
|
substantially improve performance on some designs
|
||||||
|
* Added constant folding for comparisons involving string literals
|
||||||
|
|
||||||
## v0.0.10
|
## v0.0.10
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ traverseStmtM stmt = do
|
||||||
|
|
||||||
traverseExprM :: Expr -> SC Expr
|
traverseExprM :: Expr -> SC Expr
|
||||||
traverseExprM (Cast (Left (IntegerVector kw sg rs)) value) | kw /= TBit = do
|
traverseExprM (Cast (Left (IntegerVector kw sg rs)) value) | kw /= TBit = do
|
||||||
value' <- traverseExprM value
|
value' <- fmap simplify $ traverseExprM value
|
||||||
size' <- traverseExprM size
|
size' <- traverseExprM size
|
||||||
convertCastM size' value' signed
|
convertCastM size' value' signed
|
||||||
where
|
where
|
||||||
|
|
@ -121,8 +121,9 @@ convertCastM (Number size) (Number value) signed =
|
||||||
return $ Number $
|
return $ Number $
|
||||||
numberCast signed (fromIntegral size') value
|
numberCast signed (fromIntegral size') value
|
||||||
where Just size' = numberToInteger size
|
where Just size' = numberToInteger size
|
||||||
|
convertCastM size@Number{} (String str) signed =
|
||||||
|
convertCastM size (stringToNumber str) signed
|
||||||
convertCastM size value signed = do
|
convertCastM size value signed = do
|
||||||
value' <- traverseExprM value
|
|
||||||
sizeUsesLocalVars <- embedScopes usesLocalVars size
|
sizeUsesLocalVars <- embedScopes usesLocalVars size
|
||||||
inProcedure <- withinProcedureM
|
inProcedure <- withinProcedureM
|
||||||
if not sizeUsesLocalVars || not inProcedure then do
|
if not sizeUsesLocalVars || not inProcedure then do
|
||||||
|
|
@ -135,12 +136,12 @@ convertCastM size value signed = do
|
||||||
else do
|
else do
|
||||||
details <- lookupElemM name
|
details <- lookupElemM name
|
||||||
when (details == Nothing) (injectTopItem item)
|
when (details == Nothing) (injectTopItem item)
|
||||||
return $ Call (Ident name) (Args [value'] [])
|
return $ Call (Ident name) (Args [value] [])
|
||||||
else do
|
else do
|
||||||
name <- castDeclName 0
|
name <- castDeclName 0
|
||||||
insertElem name ()
|
insertElem name ()
|
||||||
useVar <- withinStmt
|
useVar <- withinStmt
|
||||||
injectDecl $ castDecl useVar name value' size signed
|
injectDecl $ castDecl useVar name value size signed
|
||||||
return $ Ident name
|
return $ Ident name
|
||||||
|
|
||||||
-- checks if a cast size references any vars not defined at the top level scope
|
-- checks if a cast size references any vars not defined at the top level scope
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,11 @@ module Convert.ExprUtils
|
||||||
, endianCondExpr
|
, endianCondExpr
|
||||||
, endianCondRange
|
, endianCondRange
|
||||||
, dimensionsSize
|
, dimensionsSize
|
||||||
|
, stringToNumber
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Data.Bits (shiftL, shiftR)
|
import Data.Bits ((.&.), (.|.), shiftL, shiftR)
|
||||||
|
import Data.Char (ord)
|
||||||
|
|
||||||
import Convert.Traverse
|
import Convert.Traverse
|
||||||
import Language.SystemVerilog.AST
|
import Language.SystemVerilog.AST
|
||||||
|
|
@ -36,18 +38,13 @@ simplifyStep (UniOp LogNot (BinOp Ne a b)) = BinOp Eq a b
|
||||||
simplifyStep (UniOp UniSub (UniOp UniSub e)) = e
|
simplifyStep (UniOp UniSub (UniOp UniSub e)) = e
|
||||||
simplifyStep (UniOp UniSub (BinOp Sub e1 e2)) = BinOp Sub e2 e1
|
simplifyStep (UniOp UniSub (BinOp Sub e1 e2)) = BinOp Sub e2 e1
|
||||||
|
|
||||||
simplifyStep (Concat (Number n1 : Number n2 : rest)) =
|
|
||||||
simplifyStep $ Concat $ Number n : rest
|
|
||||||
where n = n1 <> n2
|
|
||||||
|
|
||||||
simplifyStep (Concat [Number (Decimal size _ value)]) =
|
simplifyStep (Concat [Number (Decimal size _ value)]) =
|
||||||
Number $ Decimal size False value
|
Number $ Decimal size False value
|
||||||
simplifyStep (Concat [Number (Based size _ base value kinds)]) =
|
simplifyStep (Concat [Number (Based size _ base value kinds)]) =
|
||||||
Number $ Based size False base value kinds
|
Number $ Based size False base value kinds
|
||||||
simplifyStep (Concat [e@Stream{}]) = e
|
simplifyStep (Concat [e@Stream{}]) = e
|
||||||
simplifyStep (Concat [e@Concat{}]) = e
|
|
||||||
simplifyStep (Concat [e@Repeat{}]) = e
|
simplifyStep (Concat [e@Repeat{}]) = e
|
||||||
simplifyStep (Concat es) = Concat $ filter (/= Concat []) es
|
simplifyStep (Concat es) = Concat $ flattenConcat es
|
||||||
simplifyStep (Repeat (Dec 0) _) = Concat []
|
simplifyStep (Repeat (Dec 0) _) = Concat []
|
||||||
simplifyStep (Repeat (Dec 1) es) = Concat es
|
simplifyStep (Repeat (Dec 1) es) = Concat es
|
||||||
simplifyStep (Mux (Number n) e1 e2) =
|
simplifyStep (Mux (Number n) e1 e2) =
|
||||||
|
|
@ -73,6 +70,16 @@ simplifyStep e@(BinOp _ (BinOp _ Number{} Number{}) Number{}) = e
|
||||||
simplifyStep (BinOp op e1 e2) = simplifyBinOp op e1 e2
|
simplifyStep (BinOp op e1 e2) = simplifyBinOp op e1 e2
|
||||||
simplifyStep other = other
|
simplifyStep other = other
|
||||||
|
|
||||||
|
-- flatten and coalesce concatenations
|
||||||
|
flattenConcat :: [Expr] -> [Expr]
|
||||||
|
flattenConcat (Number n1 : Number n2 : es) =
|
||||||
|
flattenConcat $ Number (n1 <> n2) : es
|
||||||
|
flattenConcat (Concat es1 : es2) =
|
||||||
|
flattenConcat $ es1 ++ es2
|
||||||
|
flattenConcat (e : es) =
|
||||||
|
e : flattenConcat es
|
||||||
|
flattenConcat [] = []
|
||||||
|
|
||||||
|
|
||||||
simplifyBinOp :: BinOp -> Expr -> Expr -> Expr
|
simplifyBinOp :: BinOp -> Expr -> Expr -> Expr
|
||||||
|
|
||||||
|
|
@ -107,10 +114,50 @@ simplifyBinOp Add (BinOp Sub n1@Number{} e) n2@Number{} =
|
||||||
BinOp Sub (BinOp Add n1 n2) e
|
BinOp Sub (BinOp Add n1 n2) e
|
||||||
simplifyBinOp Ge (BinOp Sub e (Dec 1)) (Dec 0) = BinOp Ge e (toDec 1)
|
simplifyBinOp Ge (BinOp Sub e (Dec 1)) (Dec 0) = BinOp Ge e (toDec 1)
|
||||||
|
|
||||||
simplifyBinOp ShiftAL (Dec x) (Dec y) = toDec $ shiftL x (fromIntegral y)
|
-- simplify bit shifts of decimal literals
|
||||||
simplifyBinOp ShiftAR (Dec x) (Dec y) = toDec $ shiftR x (fromIntegral y)
|
simplifyBinOp op (Dec x) (Number yRaw)
|
||||||
simplifyBinOp ShiftL (Dec x) (Dec y) = toDec $ shiftL x (fromIntegral y)
|
| ShiftAL <- op = decShift shiftL
|
||||||
simplifyBinOp ShiftR (Dec x) (Dec y) = toDec $ shiftR x (fromIntegral y)
|
| ShiftAR <- op = decShift shiftR
|
||||||
|
| ShiftL <- op = decShift shiftL
|
||||||
|
| ShiftR <- op = decShift shiftR
|
||||||
|
where
|
||||||
|
decShift shifter =
|
||||||
|
case numberToInteger yRaw of
|
||||||
|
Just y -> toDec $ shifter x (fromIntegral y)
|
||||||
|
Nothing -> constantFold undefined Div undefined 0
|
||||||
|
|
||||||
|
-- simply comparisons with string literals
|
||||||
|
simplifyBinOp op (Number n) (String s) | isCmpOp op =
|
||||||
|
simplifyBinOp op (Number n) (sizeStringAs s n)
|
||||||
|
simplifyBinOp op (String s) (Number n) | isCmpOp op =
|
||||||
|
simplifyBinOp op (sizeStringAs s n) (Number n)
|
||||||
|
simplifyBinOp op (String s1) (String s2) | isCmpOp op =
|
||||||
|
simplifyBinOp op (stringToNumber s1) (stringToNumber s2)
|
||||||
|
|
||||||
|
-- simply basic arithmetic comparisons
|
||||||
|
simplifyBinOp op (Number n1) (Number n2)
|
||||||
|
| Eq <- op = cmp (==)
|
||||||
|
| Ne <- op = cmp (/=)
|
||||||
|
| Lt <- op = cmp (<)
|
||||||
|
| Le <- op = cmp (<=)
|
||||||
|
| Gt <- op = cmp (>)
|
||||||
|
| Ge <- op = cmp (>=)
|
||||||
|
where
|
||||||
|
cmp :: (Integer -> Integer -> Bool) -> Expr
|
||||||
|
cmp folder =
|
||||||
|
case (numberToInteger n1', numberToInteger n2') of
|
||||||
|
(Just i1, Just i2) -> bool $ folder i1 i2
|
||||||
|
_ -> BinOp op (Number n1') (Number n2')
|
||||||
|
sg = numberIsSigned n1 && numberIsSigned n2
|
||||||
|
sz = fromIntegral $ max (numberBitLength n1) (numberBitLength n2)
|
||||||
|
n1' = numberCast sg sz n1
|
||||||
|
n2' = numberCast sg sz n2
|
||||||
|
|
||||||
|
-- simply comparisons with unbased unsized literals
|
||||||
|
simplifyBinOp op (Number n) (ConvertedUU sz v k) | isCmpOp op =
|
||||||
|
simplifyBinOp op (Number n) (uuExtend sz v k)
|
||||||
|
simplifyBinOp op (ConvertedUU sz v k) (Number n) | isCmpOp op =
|
||||||
|
simplifyBinOp op (uuExtend sz v k) (Number n)
|
||||||
|
|
||||||
simplifyBinOp op e1 e2 =
|
simplifyBinOp op e1 e2 =
|
||||||
case (e1, e2) of
|
case (e1, e2) of
|
||||||
|
|
@ -142,6 +189,8 @@ constantFold _ Gt x y = bool $ x > y
|
||||||
constantFold _ Ge x y = bool $ x >= y
|
constantFold _ Ge x y = bool $ x >= y
|
||||||
constantFold _ Lt x y = bool $ x < y
|
constantFold _ Lt x y = bool $ x < y
|
||||||
constantFold _ Le x y = bool $ x <= y
|
constantFold _ Le x y = bool $ x <= y
|
||||||
|
constantFold _ BitAnd x y = toDec $ x .&. y
|
||||||
|
constantFold _ BitOr x y = toDec $ x .|. y
|
||||||
constantFold fallback _ _ _ = fallback
|
constantFold fallback _ _ _ = fallback
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -224,3 +273,49 @@ pattern SizedRange expr = (BinOp Sub expr (RawNum 1), RawNum 0)
|
||||||
-- similar to the above pattern, we assume E >= 1 for any range like [0:E-1]
|
-- similar to the above pattern, we assume E >= 1 for any range like [0:E-1]
|
||||||
pattern RevSzRange :: Expr -> Range
|
pattern RevSzRange :: Expr -> Range
|
||||||
pattern RevSzRange expr = (RawNum 0, BinOp Sub expr (RawNum 1))
|
pattern RevSzRange expr = (RawNum 0, BinOp Sub expr (RawNum 1))
|
||||||
|
|
||||||
|
-- convert a string to decimal number
|
||||||
|
stringToNumber :: String -> Expr
|
||||||
|
stringToNumber str =
|
||||||
|
Number $ Decimal size False value
|
||||||
|
where
|
||||||
|
size = 8 * length str
|
||||||
|
value = stringToInteger str
|
||||||
|
|
||||||
|
-- convert a string to big integer
|
||||||
|
stringToInteger :: String -> Integer
|
||||||
|
stringToInteger [] = 0
|
||||||
|
stringToInteger (x : xs) =
|
||||||
|
fromIntegral (ord x) + (256 :: Integer) * stringToInteger xs
|
||||||
|
|
||||||
|
-- cast string to number at least as big as the width of the given number
|
||||||
|
sizeStringAs :: String -> Number -> Expr
|
||||||
|
sizeStringAs str num =
|
||||||
|
Cast (Left typ) (stringToNumber str)
|
||||||
|
where
|
||||||
|
typ = IntegerVector TReg Unspecified [(RawNum size, RawNum 1)]
|
||||||
|
size = max strSize numSize
|
||||||
|
strSize = fromIntegral $ 8 * length str
|
||||||
|
numSize = numberBitLength num
|
||||||
|
|
||||||
|
-- excludes wildcard and strict comparison operators
|
||||||
|
isCmpOp :: BinOp -> Bool
|
||||||
|
isCmpOp Eq = True
|
||||||
|
isCmpOp Ne = True
|
||||||
|
isCmpOp Lt = True
|
||||||
|
isCmpOp Le = True
|
||||||
|
isCmpOp Gt = True
|
||||||
|
isCmpOp Ge = True
|
||||||
|
isCmpOp _ = False
|
||||||
|
|
||||||
|
-- sign extend a converted unbased unsized literal into a based number
|
||||||
|
uuExtend :: Integer -> Integer -> Integer -> Expr
|
||||||
|
uuExtend sz v k =
|
||||||
|
Number $
|
||||||
|
numberCast False (fromIntegral sz) $
|
||||||
|
Based 1 True Hex v k
|
||||||
|
|
||||||
|
pattern ConvertedUU :: Integer -> Integer -> Integer -> Expr
|
||||||
|
pattern ConvertedUU sz v k <- Repeat
|
||||||
|
(RawNum sz)
|
||||||
|
[Number (Based 1 True Binary v k)]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
// This verifies that sv2v can evaluate certain constant expressions by
|
||||||
|
// producing iverilog-incompatible code if the expression cannot be simplified
|
||||||
|
// or is evaluated incorrectly.
|
||||||
|
`define ASSERT_TRUE(expr) if (expr) begin end else begin shortreal x; end
|
||||||
|
`define ASSERT_FALSE(expr) if (expr) begin shortreal x; end
|
||||||
|
|
||||||
|
module top;
|
||||||
|
`ASSERT_TRUE(1)
|
||||||
|
`ASSERT_FALSE(0)
|
||||||
|
|
||||||
|
`ASSERT_TRUE("inv" == "inv")
|
||||||
|
`ASSERT_TRUE(32'("inv") == "inv")
|
||||||
|
`ASSERT_TRUE("inv" == 32'("inv"))
|
||||||
|
`ASSERT_TRUE(24'("inv") == "inv")
|
||||||
|
`ASSERT_TRUE("inv" == 24'("inv"))
|
||||||
|
|
||||||
|
`ASSERT_FALSE("invv" == "inv")
|
||||||
|
`ASSERT_FALSE("0inv" == "inv")
|
||||||
|
`ASSERT_TRUE("invv" != "inv")
|
||||||
|
`ASSERT_TRUE("0inv" != "inv")
|
||||||
|
|
||||||
|
`ASSERT_TRUE(24'("inv0") == "inv")
|
||||||
|
`ASSERT_TRUE(24'("0inv") != "inv")
|
||||||
|
`ASSERT_FALSE("inv" == 0)
|
||||||
|
`ASSERT_FALSE("inv" == '0)
|
||||||
|
`ASSERT_FALSE('0 == "inv")
|
||||||
|
`ASSERT_FALSE("inv" == 1'b0)
|
||||||
|
`ASSERT_FALSE("inv" == 2'd0)
|
||||||
|
`ASSERT_FALSE("inv" == 1'sb0)
|
||||||
|
|
||||||
|
`ASSERT_TRUE(1'sb0 < 1'd1)
|
||||||
|
`ASSERT_TRUE(1'sb0 <= 1'd0)
|
||||||
|
`ASSERT_FALSE(1'sb0 > 1'd1)
|
||||||
|
`ASSERT_TRUE(1'sb0 >= 1'd0)
|
||||||
|
|
||||||
|
`ASSERT_TRUE((1 | 2) == 3)
|
||||||
|
`ASSERT_TRUE((13 & 7) == 5)
|
||||||
|
|
||||||
|
`ASSERT_TRUE((1 << 1) == 2)
|
||||||
|
`ASSERT_TRUE((3 >> 1) == 1)
|
||||||
|
`ASSERT_TRUE((1 <<< 1) == 2)
|
||||||
|
`ASSERT_TRUE((3 >>> 1) == 1)
|
||||||
|
|
||||||
|
`ASSERT_TRUE(5'{4'hF, 3'{1'b1, 1'b1}} == 27)
|
||||||
|
`ASSERT_TRUE(5'{{{1'b1, 1'b1}, {1'b1, 1'b1}}} == 15)
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
module top; endmodule
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
// pattern: size cast width 'shxxxxxxxx is not an integer
|
||||||
|
// location: size_cast_xpr_lit.sv:4:13
|
||||||
|
module top;
|
||||||
|
initial $display((1 << 'x)'(2));
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
// pattern: size cast width 'shxxxxxxxx is not an integer
|
||||||
|
// location: size_cast_xpr_var.sv:5:13
|
||||||
|
module top;
|
||||||
|
wire x = 0;
|
||||||
|
initial $display((1 << 'x)'(x));
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue