Commit 59d37468 by Zachary Snow

fix internal interpretation of negative number literals

- detect and forbid non-positive size casts
- detect and forbid negative struct pattern literal indices
- avoid invalid constant folding of negative based literals
parent 7e9fb337
## Unreleased
* Non-positive integer size casts are now detected and forbidden
* Negative indices in struct pattern literals are now detected and forbidden
## v0.0.8 ## v0.0.8
Future releases will have complete change logs. Future releases will have complete change logs.
...@@ -110,12 +110,17 @@ traverseExprM other = ...@@ -110,12 +110,17 @@ traverseExprM other =
traverseSinglyNestedExprsM traverseExprM other traverseSinglyNestedExprsM traverseExprM other
convertCastM :: Expr -> Expr -> Bool -> SC Expr convertCastM :: Expr -> Expr -> Bool -> SC Expr
convertCastM (Number size) _ _
| maybeInt == Nothing = illegal "an integer"
| int <= 0 = illegal "a positive integer"
where
maybeInt = numberToInteger size
Just int = maybeInt
illegal s = error $ "size cast width " ++ show size ++ " is not " ++ s
convertCastM (Number size) (Number value) signed = convertCastM (Number size) (Number value) signed =
return $ Number $ return $ Number $
case numberToInteger size of numberCast signed (fromIntegral size') value
Just size' -> numberCast signed (fromIntegral size') value where Just size' = numberToInteger size
Nothing -> error $ "size cast width " ++ show size
++ " is not an integer"
convertCastM size value signed = do convertCastM size value signed = do
value' <- traverseExprM value value' <- traverseExprM value
sizeUsesLocalVars <- embedScopes usesLocalVars size sizeUsesLocalVars <- embedScopes usesLocalVars size
...@@ -177,11 +182,8 @@ castFnName size signed = ...@@ -177,11 +182,8 @@ castFnName size signed =
"sv2v_cast_" ++ sizeStr ++ suffix "sv2v_cast_" ++ sizeStr ++ suffix
where where
sizeStr = case size of sizeStr = case size of
Number n -> Number n -> show v
case numberToInteger n of where Just v = numberToInteger n
Just v -> show v
_ -> error $ "size cast width " ++ show n
++ " is not an integer"
_ -> shortHash size _ -> shortHash size
suffix = if signed then "_signed" else "" suffix = if signed then "_signed" else ""
......
...@@ -177,7 +177,7 @@ pattern NegDec :: Integer -> Expr ...@@ -177,7 +177,7 @@ pattern NegDec :: Integer -> Expr
pattern NegDec n <- UniOp UniSub (Dec n) pattern NegDec n <- UniOp UniSub (Dec n)
pattern Bas :: Integer -> Expr pattern Bas :: Integer -> Expr
pattern Bas n <- Number (Based _ _ _ n 0) pattern Bas n <- Number (Based _ False _ n 0)
-- returns the size of a range -- returns the size of a range
......
...@@ -229,7 +229,8 @@ convertExpr (struct @ (Struct _ fields [])) (Pattern itemsOrig) = ...@@ -229,7 +229,8 @@ convertExpr (struct @ (Struct _ fields [])) (Pattern itemsOrig) =
isNumbered (Right (Number n)) = isNumbered (Right (Number n)) =
if maybeIndex == Nothing if maybeIndex == Nothing
then error msgNonInteger then error msgNonInteger
else index < length fieldNames || error msgOutOfBounds else 0 <= index && index < length fieldNames
|| error msgOutOfBounds
where where
maybeIndex = fmap fromIntegral $ numberToInteger n maybeIndex = fmap fromIntegral $ numberToInteger n
Just index = maybeIndex Just index = maybeIndex
......
...@@ -128,6 +128,9 @@ traverseExprM other = ...@@ -128,6 +128,9 @@ traverseExprM other =
-- carry forward the signedness of the expression when cast to the given size -- carry forward the signedness of the expression when cast to the given size
elaborateSizeCast :: Expr -> Expr -> ST Expr elaborateSizeCast :: Expr -> Expr -> ST Expr
elaborateSizeCast (Number size) _ | Just 0 == numberToInteger size =
-- special case because zero-width ranges cannot be represented
error $ "size cast width " ++ show size ++ " is not a positive integer"
elaborateSizeCast size value = do elaborateSizeCast size value = do
t <- typeof value t <- typeof value
force <- isStringParam value force <- isStringParam value
......
...@@ -17,7 +17,7 @@ module Language.SystemVerilog.AST.Number ...@@ -17,7 +17,7 @@ module Language.SystemVerilog.AST.Number
, bitToVK , bitToVK
) where ) where
import Data.Bits (shiftL) import Data.Bits ((.&.), shiftL)
import Data.Char (digitToInt, intToDigit, toLower) import Data.Char (digitToInt, intToDigit, toLower)
import Data.List (elemIndex) import Data.List (elemIndex)
import Text.Read (readMaybe) import Text.Read (readMaybe)
...@@ -220,8 +220,13 @@ numberToInteger :: Number -> Maybe Integer ...@@ -220,8 +220,13 @@ numberToInteger :: Number -> Maybe Integer
numberToInteger (UnbasedUnsized Bit1) = Just 1 numberToInteger (UnbasedUnsized Bit1) = Just 1
numberToInteger (UnbasedUnsized Bit0) = Just 0 numberToInteger (UnbasedUnsized Bit0) = Just 0
numberToInteger UnbasedUnsized{} = Nothing numberToInteger UnbasedUnsized{} = Nothing
numberToInteger (Decimal _ _ num) = Just num numberToInteger (Decimal sz sg num)
numberToInteger (Based _ _ _ num 0) = Just num | not sg || num .&. pow == 0 = Just num
| num == 1 = Just $ -1
| otherwise = Just $ negate $ num - pow
where pow = 2 ^ (abs sz - 1)
numberToInteger (Based sz sg _ num 0) =
numberToInteger $ Decimal sz sg num
numberToInteger Based{} = Nothing numberToInteger Based{} = Nothing
-- return the number of bits in a number (i.e. ilog2) -- return the number of bits in a number (i.e. ilog2)
......
...@@ -40,6 +40,10 @@ module top; ...@@ -40,6 +40,10 @@ module top;
$display("args %b", $size(RamPair, 1)); $display("args %b", $size(RamPair, 1));
$display("args %b", $size(RamPair, 1'b1)); $display("args %b", $size(RamPair, 1'b1));
$display("args %b", $size(RamPair, 1'sb1));
$display("args %b", $size(RamPair, 2'sb1));
$display("args %b", $size(RamPair, 2'sb01));
$display("args %b", $size(RamPair, 2'sb11));
$display("args %b", $size(RamPair, '1)); $display("args %b", $size(RamPair, '1));
$display("args %b", $size(RamPair, 'o1)); $display("args %b", $size(RamPair, 'o1));
$display("args %b", $size(RamPair, 1'h1)); $display("args %b", $size(RamPair, 1'h1));
......
...@@ -37,6 +37,10 @@ module top; ...@@ -37,6 +37,10 @@ module top;
$display("args %b", 2); $display("args %b", 2);
$display("args %b", 2); $display("args %b", 2);
$display("args %b", 1'bx);
$display("args %b", 2);
$display("args %b", 2);
$display("args %b", 1'bx);
$display("args %b", 2); $display("args %b", 2);
$display("args %b", 2); $display("args %b", 2);
$display("args %b", 2); $display("args %b", 2);
......
// pattern: size cast width 1'sb1 is not a positive integer
module top;
initial $display((1'sb1)'(2));
endmodule
// pattern: size cast width 2'sb11 is not a positive integer
module top;
initial $display((2'sb11)'(2));
endmodule
// pattern: size cast width 1'sb1 is not a positive integer
module top;
wire x = 0;
initial $display((1'sb1)'(x));
endmodule
// pattern: size cast width 2'sb11 is not a positive integer
module top;
wire x = 0;
initial $display((2'sb11)'(x));
endmodule
// pattern: size cast width 1'bx is not an integer
module top;
wire x = 0;
initial $display((1'bx)'(x));
endmodule
// pattern: size cast width 0 is not a positive integer
module top;
initial $display((0)'(2));
endmodule
// pattern: size cast width 0 is not a positive integer
module top;
wire x = 0;
initial $display((0)'(x));
endmodule
// pattern: pattern index -1 is out of bounds for struct packed \{..logic x;.\}
module top;
struct packed {
logic x;
} s = '{ 1'sb1: 1 };
endmodule
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