Commit ed09fe88 by Zachary Snow

support assignments within expressions

parent 4ced649a
......@@ -2,6 +2,7 @@
### New Features
* Added support for assignments within expressions (e.g., `x = ++y;`)
* Added support for excluding the conversion of unbased unsized literals (e.g.,
`'1`, `'x`) via `--exclude UnbasedUniszed`
* Added support for enumerated type ranges (e.g., `enum { X[3:5] }`)
......
......@@ -21,6 +21,7 @@ import qualified Convert.DoWhile
import qualified Convert.DuplicateGenvar
import qualified Convert.EmptyArgs
import qualified Convert.Enum
import qualified Convert.ExprAsgn
import qualified Convert.ForAsgn
import qualified Convert.Foreach
import qualified Convert.FuncRet
......@@ -101,6 +102,7 @@ initialPhases :: Selector -> [Phase]
initialPhases selectExclude =
[ Convert.ForAsgn.convert
, Convert.Jump.convert
, Convert.ExprAsgn.convert
, Convert.KWArgs.convert
, Convert.Unique.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
e2' <- exprMapper e2
e3' <- exprMapper 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
traverseSinglyNestedExprs :: Mapper Expr -> Mapper Expr
......
......@@ -61,6 +61,7 @@ data Expr
| Pattern [(TypeOrExpr, Expr)]
| Inside Expr [Expr]
| MinTypMax Expr Expr Expr
| ExprAsgn Expr Expr
| Nil
deriving Eq
......@@ -92,6 +93,7 @@ instance Show Expr where
showPatternItem (Left t, v) = printf "%s: %s" tStr (show v)
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 (ExprAsgn l r) = printf "(%s = %s)" (show l) (show r)
show e@UniOp{} = showsPrec 0 e ""
show e@BinOp{} = showsPrec 0 e ""
show e@Dot {} = showsPrec 0 e ""
......
......@@ -1385,6 +1385,11 @@ Expr :: { Expr }
| "^" Expr %prec REDUCE_OP { UniOp RedXor $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 }
: Expr { $1 }
......@@ -1786,4 +1791,24 @@ makeDPIImport :: String -> DPIImportProperty -> Identifier
-> (Type, Identifier, [Decl]) -> PackageItem
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
Convert.DuplicateGenvar
Convert.EmptyArgs
Convert.Enum
Convert.ExprAsgn
Convert.ExprUtils
Convert.ForAsgn
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