mirror of https://github.com/zachjs/sv2v.git
improved handling of break statement
- fix preservation of loop variables when breaking - extend Yosys-compatible constant loop conversion to support loop variables declared outside of the looop
This commit is contained in:
parent
04d6fa6199
commit
44afcf5b29
|
|
@ -122,6 +122,9 @@ pattern SimpleLoopInits :: String -> Type -> Identifier -> Expr
|
|||
pattern SimpleLoopInits msg typ var expr =
|
||||
Left [CommentDecl msg, Variable Local typ var [] expr]
|
||||
|
||||
pattern SimpleLoopInitsAlt :: String -> Expr -> Either [Decl] [(LHS, Expr)]
|
||||
pattern SimpleLoopInitsAlt var expr = Right [(LHSIdent var, expr)]
|
||||
|
||||
pattern SimpleLoopGuard :: BinOp -> Identifier -> Expr -> Expr
|
||||
pattern SimpleLoopGuard cmp var bound = BinOp cmp (Ident var) bound
|
||||
|
||||
|
|
@ -179,19 +182,32 @@ convertStmt (Case unique kw expr cases) = do
|
|||
convertStmt (For
|
||||
(inits @ (SimpleLoopInits _ _ var1 _))
|
||||
(comp @ (SimpleLoopGuard _ var2 _))
|
||||
(incr @ (SimpleLoopIncrs var3 _ _))
|
||||
stmt) =
|
||||
if var1 /= var2 || var2 /= var3
|
||||
then convertLoop False loop comp stmt
|
||||
else convertLoop True loop comp stmt
|
||||
where loop c s = For inits c incr s
|
||||
(incr @ (SimpleLoopIncrs var3 _ _)) stmt) =
|
||||
convertLoop localInfo loop comp incr stmt
|
||||
where
|
||||
loop c i s = For inits c i s
|
||||
localInfo = if var1 /= var2 || var2 /= var3
|
||||
then Nothing
|
||||
else Just ""
|
||||
convertStmt (For
|
||||
(inits @ (SimpleLoopInitsAlt var1 _))
|
||||
(comp @ (SimpleLoopGuard _ var2 _))
|
||||
(incr @ (SimpleLoopIncrs var3 _ _)) stmt) =
|
||||
convertLoop localInfo loop comp incr stmt
|
||||
where
|
||||
loop c i s = For inits c i s
|
||||
localInfo = if var1 /= var2 || var2 /= var3
|
||||
then Nothing
|
||||
else Just var1
|
||||
convertStmt (For inits comp incr stmt) =
|
||||
convertLoop False loop comp stmt
|
||||
where loop c s = For inits c incr s
|
||||
convertLoop Nothing loop comp incr stmt
|
||||
where loop c i s = For inits c i s
|
||||
convertStmt (While comp stmt) =
|
||||
convertLoop False While comp stmt
|
||||
convertLoop Nothing loop comp [] stmt
|
||||
where loop c _ s = While c s
|
||||
convertStmt (DoWhile comp stmt) =
|
||||
convertLoop False DoWhile comp stmt
|
||||
convertLoop Nothing loop comp [] stmt
|
||||
where loop c _ s = DoWhile c s
|
||||
|
||||
convertStmt (Continue) = do
|
||||
loopDepth <- gets sLoopDepth
|
||||
|
|
@ -255,8 +271,11 @@ convertSubStmt stmt = do
|
|||
put origState
|
||||
return (stmt', hasJump)
|
||||
|
||||
convertLoop :: Bool -> (Expr -> Stmt -> Stmt) -> Expr -> Stmt -> State Info Stmt
|
||||
convertLoop local loop comp stmt = do
|
||||
type Incr = (LHS, AsgnOp, Expr)
|
||||
|
||||
convertLoop :: Maybe Identifier -> (Expr -> [Incr] -> Stmt -> Stmt) -> Expr
|
||||
-> [Incr] -> Stmt -> State Info Stmt
|
||||
convertLoop localInfo loop comp incr stmt = do
|
||||
-- save the loop state and increment loop depth
|
||||
Info { sLoopDepth = origLoopDepth, sHasJump = origHasJump } <- get
|
||||
assertMsg (not origHasJump) "has jump invariant failed"
|
||||
|
|
@ -268,13 +287,26 @@ convertLoop local loop comp stmt = do
|
|||
assertMsg (origLoopDepth + 1 == afterLoopDepth) "loop depth invariant failed"
|
||||
modify $ \s -> s { sLoopDepth = origLoopDepth }
|
||||
|
||||
let useBreakVar = local && not (null localVar)
|
||||
let breakVarDeclRaw = Variable Local (TypeOf $ Ident localVar) breakVar [] Nil
|
||||
let breakVarDecl = if useBreakVar then breakVarDeclRaw else CommentDecl "no-op"
|
||||
let updateBreakVar = if useBreakVar then asgn breakVar $ Ident localVar else Null
|
||||
|
||||
let keepRunning = BinOp Lt (Ident jumpState) jsBreak
|
||||
let pushBreakVar = if useBreakVar
|
||||
then If NoCheck (UniOp LogNot keepRunning)
|
||||
(asgn localVar $ Ident breakVar) Null
|
||||
else Null
|
||||
let comp' = if local then comp else BinOp LogAnd comp keepRunning
|
||||
let incr' = if local then incr else map (stubIncr keepRunning) incr
|
||||
let body = Block Seq "" [] $
|
||||
[ asgn jumpState jsNone
|
||||
, stmt'
|
||||
]
|
||||
let body' = if local then If NoCheck keepRunning body Null else body
|
||||
let body' = if local
|
||||
then If NoCheck keepRunning
|
||||
(Block Seq "" [] [body, updateBreakVar]) Null
|
||||
else body
|
||||
let jsStackIdent = jumpState ++ "_" ++ show origLoopDepth
|
||||
let jsStackDecl = Variable Local jumpStateType jsStackIdent []
|
||||
(Ident jumpState)
|
||||
|
|
@ -289,19 +321,36 @@ convertLoop local loop comp stmt = do
|
|||
|
||||
return $
|
||||
if not afterHasJump then
|
||||
loop comp stmt'
|
||||
loop comp incr stmt'
|
||||
else if origLoopDepth == 0 then
|
||||
Block Seq "" []
|
||||
[ loop comp' body'
|
||||
Block Seq "" [ breakVarDecl ]
|
||||
[ loop comp' incr' body'
|
||||
, pushBreakVar
|
||||
, jsCheckReturn
|
||||
]
|
||||
else
|
||||
Block Seq ""
|
||||
[ jsStackDecl ]
|
||||
[ loop comp' body'
|
||||
[ breakVarDecl, jsStackDecl ]
|
||||
[ loop comp' incr' body'
|
||||
, pushBreakVar
|
||||
, jsStackRestore
|
||||
]
|
||||
|
||||
where
|
||||
breakVar = "_sv2v_value_on_break"
|
||||
local = localInfo /= Nothing
|
||||
Just localVar = localInfo
|
||||
|
||||
stubIncr :: Expr -> Incr -> Incr
|
||||
stubIncr keepRunning (lhs, AsgnOpEq, expr) =
|
||||
(lhs, AsgnOpEq, expr')
|
||||
where expr' = Mux keepRunning expr (lhsToExpr lhs)
|
||||
stubIncr keepRunning (lhs, op, expr) =
|
||||
stubIncr keepRunning (lhs, AsgnOpEq, expr')
|
||||
where
|
||||
AsgnOp binop = op
|
||||
expr' = BinOp binop (lhsToExpr lhs) expr
|
||||
|
||||
jumpStateType :: Type
|
||||
jumpStateType = IntegerVector TBit Unspecified [(RawNum 0, RawNum 1)]
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,49 @@ module top;
|
|||
f = f * 2;
|
||||
end
|
||||
endfunction
|
||||
function automatic integer g;
|
||||
input integer inp;
|
||||
integer idx;
|
||||
g = 1;
|
||||
for (idx = 0; idx < inp; idx = idx + 1) begin
|
||||
if (g == 32)
|
||||
break;
|
||||
g = g * 2;
|
||||
end
|
||||
g += idx;
|
||||
endfunction
|
||||
function automatic integer h;
|
||||
input integer inp;
|
||||
integer idx;
|
||||
h = 1;
|
||||
for (idx = 0; idx + 1 < 1 + inp; idx = idx + 1) begin
|
||||
if (h == 32)
|
||||
break;
|
||||
h = h * 2;
|
||||
end
|
||||
h += idx + 1;
|
||||
endfunction
|
||||
function automatic integer j;
|
||||
input integer inp;
|
||||
for (j = 0; j < inp; j = j + 1)
|
||||
if (j == 3)
|
||||
return j;
|
||||
j *= 2;
|
||||
endfunction
|
||||
function automatic integer k;
|
||||
input integer inp;
|
||||
for (k = 0; k + 1 < 1 + inp; k = k + 1)
|
||||
if (k == 3)
|
||||
return k * 3;
|
||||
k = k * 2 + 1;
|
||||
endfunction
|
||||
integer i;
|
||||
initial
|
||||
for (i = 0; i < 10; i = i + 1)
|
||||
for (i = 0; i < 10; i = i + 1) begin
|
||||
$display("f(%0d) = %0d", i, f(i));
|
||||
$display("g(%0d) = %0d", i, g(i));
|
||||
$display("h(%0d) = %0d", i, h(i));
|
||||
$display("j(%0d) = %0d", i, j(i));
|
||||
$display("k(%0d) = %0d", i, k(i));
|
||||
end
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -6,8 +6,41 @@ module top;
|
|||
else
|
||||
f = 2 ** inp;
|
||||
endfunction
|
||||
function automatic integer g;
|
||||
input integer inp;
|
||||
if (inp > 5)
|
||||
g = 32 + 5;
|
||||
else
|
||||
g = 2 ** inp + inp;
|
||||
endfunction
|
||||
function automatic integer h;
|
||||
input integer inp;
|
||||
if (inp > 5)
|
||||
h = 32 + 5 + 1;
|
||||
else
|
||||
h = 2 ** inp + inp + 1;
|
||||
endfunction
|
||||
function automatic integer j;
|
||||
input integer inp;
|
||||
if (inp > 3)
|
||||
j = 3;
|
||||
else
|
||||
j = inp * 2;
|
||||
endfunction
|
||||
function automatic integer k;
|
||||
input integer inp;
|
||||
if (inp > 3)
|
||||
k = 3 * 3;
|
||||
else
|
||||
k = inp * 2 + 1;
|
||||
endfunction
|
||||
integer i;
|
||||
initial
|
||||
for (i = 0; i < 10; i = i + 1)
|
||||
for (i = 0; i < 10; i = i + 1) begin
|
||||
$display("f(%0d) = %0d", i, f(i));
|
||||
$display("g(%0d) = %0d", i, g(i));
|
||||
$display("h(%0d) = %0d", i, h(i));
|
||||
$display("j(%0d) = %0d", i, j(i));
|
||||
$display("k(%0d) = %0d", i, k(i));
|
||||
end
|
||||
endmodule
|
||||
|
|
|
|||
Loading…
Reference in New Issue