Commit ed09fe88 by Zachary Snow

support assignments within expressions

parent 4ced649a
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
### New Features ### New Features
* Added support for assignments within expressions (e.g., `x = ++y;`)
* Added support for excluding the conversion of unbased unsized literals (e.g., * Added support for excluding the conversion of unbased unsized literals (e.g.,
`'1`, `'x`) via `--exclude UnbasedUniszed` `'1`, `'x`) via `--exclude UnbasedUniszed`
* Added support for enumerated type ranges (e.g., `enum { X[3:5] }`) * Added support for enumerated type ranges (e.g., `enum { X[3:5] }`)
......
...@@ -21,6 +21,7 @@ import qualified Convert.DoWhile ...@@ -21,6 +21,7 @@ import qualified Convert.DoWhile
import qualified Convert.DuplicateGenvar import qualified Convert.DuplicateGenvar
import qualified Convert.EmptyArgs import qualified Convert.EmptyArgs
import qualified Convert.Enum import qualified Convert.Enum
import qualified Convert.ExprAsgn
import qualified Convert.ForAsgn import qualified Convert.ForAsgn
import qualified Convert.Foreach import qualified Convert.Foreach
import qualified Convert.FuncRet import qualified Convert.FuncRet
...@@ -101,6 +102,7 @@ initialPhases :: Selector -> [Phase] ...@@ -101,6 +102,7 @@ initialPhases :: Selector -> [Phase]
initialPhases selectExclude = initialPhases selectExclude =
[ Convert.ForAsgn.convert [ Convert.ForAsgn.convert
, Convert.Jump.convert , Convert.Jump.convert
, Convert.ExprAsgn.convert
, Convert.KWArgs.convert , Convert.KWArgs.convert
, Convert.Unique.convert , Convert.Unique.convert
, Convert.SenseEdge.convert , Convert.SenseEdge.convert
......
{-# LANGUAGE PatternSynonyms #-}
{- sv2v
- Author: Zachary Snow <zach@zachjs.com>
-
- Conversion for assignments within expressions
-
- IEEE 1800-2017 Section 11.3.6 states that assignments within expressions can
- only appear in procedural statements, though some tools support them in other
- contexts. We do not currently raise an error for assignments within
- expressions in unsupported contexts.
-
- Assignment expressions are replaced with the LHS, with the LHS being updated
- in a preceding statement. For post-increment operations, a pre-increment is
- performed and then the increment is reversed in the expression.
-
- This conversion occurs after the elaboration of `do` `while` loops and
- `foreach` loops, but before the elaboration of jumps and extra `for` loop
- initializations.
-}
module Convert.ExprAsgn (convert) where
import Control.Monad.Writer.Strict
import Data.Bitraversable (bimapM)
import Convert.Traverse
import Language.SystemVerilog.AST
convert :: [AST] -> [AST]
convert = map $ traverseDescriptions $ traverseModuleItems $
traverseStmts convertStmt
convertStmt :: Stmt -> Stmt
-- assignment expressions in a loop guard
convertStmt (While cond stmt) =
if null add
then While cond stmt'
else block $ add ++ [While cond' $ injectLoopIter add stmt']
where
(cond', add) = runWriter $ convertExpr cond
stmt' = convertStmt stmt
-- assignment expressions can appear in any part of the for loop
convertStmt (For inits cond incrs stmt) =
if null initsAdd && null condAdd && null incrsAdd
then For inits cond incrs stmt'
else For initsCombined cond' incrs' $
injectLoopIter (incrsAdd ++ condAdd) stmt'
where
(inits', initsAdd) = runWriter $ mapM convertInit inits
(cond', condAdd) = runWriter $ convertExpr cond
(incrs', incrsAdd) = runWriter $ mapM convertIncr incrs
stmt' = convertStmt stmt
initsCombined = map toInit initsAdd ++ inits' ++ map toInit condAdd
-- assignment expressions in other statements are added in front
convertStmt stmt =
traverseSinglyNestedStmts convertStmt $
if null add
then stmt
else block $ add ++ [stmt']
where (stmt', add) = runWriter $ traverseStmtExprsM convertExpr stmt
-- helper for creating simple blocks
block :: [Stmt] -> Stmt
block = Block Seq "" []
-- add statements before the loop guard is checked
injectLoopIter :: [Stmt] -> Stmt -> Stmt
injectLoopIter add stmt = block $ beforeContinue add stmt : add
-- add statements before every `continue` in the loop
beforeContinue :: [Stmt] -> Stmt -> Stmt
beforeContinue _ stmt@While{} = stmt
beforeContinue _ stmt@For{} = stmt
beforeContinue add Continue =
block $ add ++ [Continue]
beforeContinue add stmt =
traverseSinglyNestedStmts (beforeContinue add) stmt
-- reversible pattern to unwrap in for loops
pattern AsgnStmt :: LHS -> Expr -> Stmt
pattern AsgnStmt lhs expr = Asgn AsgnOpEq Nothing lhs expr
toInit :: Stmt -> (LHS, Expr)
toInit stmt = (lhs, expr)
where AsgnStmt lhs expr = stmt
-- functions which convert and collect assignment expressions
type Converter t = t -> Writer [Stmt] t
convertExpr :: Converter Expr
convertExpr (ExprAsgn l r) = do
l' <- convertExpr l
r' <- convertExpr r
let Just lhs = exprToLHS l' -- checked by parser
tell [AsgnStmt lhs r']
return l'
convertExpr expr =
traverseSinglyNestedExprsM convertExpr expr
convertLHS :: Converter LHS
convertLHS = traverseNestedLHSsM $ traverseLHSExprsM convertExpr
convertInit :: Converter (LHS, Expr)
convertInit = bimapM convertLHS convertExpr
convertIncr :: Converter (LHS, AsgnOp, Expr)
convertIncr (lhs, op, expr) = do
lhs' <- convertLHS lhs
expr' <- convertExpr expr
return (lhs', op, expr')
...@@ -497,6 +497,10 @@ traverseSinglyNestedExprsM exprMapper = em ...@@ -497,6 +497,10 @@ traverseSinglyNestedExprsM exprMapper = em
e2' <- exprMapper e2 e2' <- exprMapper e2
e3' <- exprMapper e3 e3' <- exprMapper e3
return $ MinTypMax e1' e2' e3' return $ MinTypMax e1' e2' e3'
em (ExprAsgn e1 e2) = do
e1' <- exprMapper e1
e2' <- exprMapper e2
return $ ExprAsgn e1' e2'
em (Nil) = return Nil em (Nil) = return Nil
traverseSinglyNestedExprs :: Mapper Expr -> Mapper Expr traverseSinglyNestedExprs :: Mapper Expr -> Mapper Expr
......
...@@ -61,6 +61,7 @@ data Expr ...@@ -61,6 +61,7 @@ data Expr
| Pattern [(TypeOrExpr, Expr)] | Pattern [(TypeOrExpr, Expr)]
| Inside Expr [Expr] | Inside Expr [Expr]
| MinTypMax Expr Expr Expr | MinTypMax Expr Expr Expr
| ExprAsgn Expr Expr
| Nil | Nil
deriving Eq deriving Eq
...@@ -92,6 +93,7 @@ instance Show Expr where ...@@ -92,6 +93,7 @@ instance Show Expr where
showPatternItem (Left t, v) = printf "%s: %s" tStr (show v) showPatternItem (Left t, v) = printf "%s: %s" tStr (show v)
where tStr = if null (show t) then "default" else show t where tStr = if null (show t) then "default" else show t
show (MinTypMax a b c) = printf "(%s : %s : %s)" (show a) (show b) (show c) show (MinTypMax a b c) = printf "(%s : %s : %s)" (show a) (show b) (show c)
show (ExprAsgn l r) = printf "(%s = %s)" (show l) (show r)
show e@UniOp{} = showsPrec 0 e "" show e@UniOp{} = showsPrec 0 e ""
show e@BinOp{} = showsPrec 0 e "" show e@BinOp{} = showsPrec 0 e ""
show e@Dot {} = showsPrec 0 e "" show e@Dot {} = showsPrec 0 e ""
......
...@@ -1385,6 +1385,11 @@ Expr :: { Expr } ...@@ -1385,6 +1385,11 @@ Expr :: { Expr }
| "^" Expr %prec REDUCE_OP { UniOp RedXor $2 } | "^" Expr %prec REDUCE_OP { UniOp RedXor $2 }
| "~^" Expr %prec REDUCE_OP { UniOp RedXnor $2 } | "~^" Expr %prec REDUCE_OP { UniOp RedXnor $2 }
| "^~" Expr %prec REDUCE_OP { UniOp RedXnor $2 } | "^~" Expr %prec REDUCE_OP { UniOp RedXnor $2 }
-- assignments within expressions
| "(" Expr "=" Expr ")" {% makeExprAsgn (tokenPosition $3, AsgnOpEq) $2 $4 }
| "(" Expr AsgnBinOpP Expr ")" {% makeExprAsgn $3 $2 $4 }
| Expr IncOrDecOperatorP {% makeIncrExprAsgn True $2 $1 }
| IncOrDecOperatorP Expr %prec "++" {% makeIncrExprAsgn False $1 $2 }
ExprOrNil :: { Expr } ExprOrNil :: { Expr }
: Expr { $1 } : Expr { $1 }
...@@ -1786,4 +1791,24 @@ makeDPIImport :: String -> DPIImportProperty -> Identifier ...@@ -1786,4 +1791,24 @@ makeDPIImport :: String -> DPIImportProperty -> Identifier
-> (Type, Identifier, [Decl]) -> PackageItem -> (Type, Identifier, [Decl]) -> PackageItem
makeDPIImport a b c (d, e, f) = DPIImport a b c d e f makeDPIImport a b c (d, e, f) = DPIImport a b c d e f
makeExprAsgn :: (Position, AsgnOp) -> Expr -> Expr -> ParseState Expr
makeExprAsgn (pos, AsgnOpEq) l r = do
case exprToLHS l of
Just{} -> return ()
Nothing -> parseError pos $ "cannot convert expression to LHS: " ++ show l
return $ ExprAsgn l r
makeExprAsgn (pos, op) l r =
makeExprAsgn (pos, AsgnOpEq) l r'
where
AsgnOp binop = op
r' = BinOp binop l r
makeIncrExprAsgn :: Bool -> (Position, BinOp) -> Expr -> ParseState Expr
makeIncrExprAsgn False (pos, op) expr =
makeExprAsgn (pos, AsgnOp op) expr (RawNum 1)
makeIncrExprAsgn True (pos, op) expr = do
expr' <- makeIncrExprAsgn False (pos, op) expr
return $ BinOp op expr' minusOne
where minusOne = Number $ Decimal 1 True 1
} }
...@@ -72,6 +72,7 @@ executable sv2v ...@@ -72,6 +72,7 @@ executable sv2v
Convert.DuplicateGenvar Convert.DuplicateGenvar
Convert.EmptyArgs Convert.EmptyArgs
Convert.Enum Convert.Enum
Convert.ExprAsgn
Convert.ExprUtils Convert.ExprUtils
Convert.ForAsgn Convert.ForAsgn
Convert.Foreach Convert.Foreach
......
module top;
integer i;
byte b;
shortint s;
initial begin
$monitor("%2d %b %b %b", $time, i, b, s);
#1 i = (b = (s = 0));
#1 i = 1;
#1 i = {1'bx, b++, 1'bx};
#1 i = {1'bx, b--, 1'bx};
#1 i = {1'bx, ++b, 1'bx};
#1 i = {1'bx, --b, 1'bx};
#1 i = 3;
while (--i) begin
if (i == 2) begin
s++;
#10;
end
else if (i == 1) begin
b++;
#3 continue;
$display("UNREACHABLE");
end
b--;
#1;
end
#1;
for (i[i++] = s--; b++ - 10 != s--; i[++i]++) begin
#1;
if (i & 1)
continue;
#10;
end
end
endmodule
module top;
integer i;
reg signed [7:0] b;
reg signed [15:0] s;
initial begin
$monitor("%2d %b %b %b", $time, i, b, s);
#1;
s = 0;
b = 0;
i = 0;
#1 i = 1;
#1;
b = b + 1;
i = {1'bx, b - 8'b1, 1'bx};
#1;
b = b - 1;
i = {1'bx, b + 8'b1, 1'bx};
#1;
b = b + 1;
i = {1'bx, b, 1'bx};
#1;
b = b - 1;
i = {1'bx, b, 1'bx};
#1;
i = 3;
i = i - 1;
s = s + 1;
#10;
b = b - 1;
#1;
i = i - 1;
b = b + 1;
#3;
i = i - 1;
#1;
i = i + 1;
s = s - 1;
i[i] = s;
b = b + 1;
s = s - 1;
while (b - 1 - 10 != s + 1) begin
#1;
if (!(i & 1))
#10;
i = i + 1;
i[i] = i[i] + 1;
b = b + 1;
s = s - 1;
end
end
endmodule
// pattern: cannot convert expression to LHS
// location: asgn_expr_non_lhs.sv:5:20
module top;
integer x;
initial x = (1 = x);
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