Commit 44afcf5b by Zachary Snow

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
parent 04d6fa61
......@@ -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
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