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 ...@@ -122,6 +122,9 @@ pattern SimpleLoopInits :: String -> Type -> Identifier -> Expr
pattern SimpleLoopInits msg typ var expr = pattern SimpleLoopInits msg typ var expr =
Left [CommentDecl msg, Variable Local 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 :: BinOp -> Identifier -> Expr -> Expr
pattern SimpleLoopGuard cmp var bound = BinOp cmp (Ident var) bound pattern SimpleLoopGuard cmp var bound = BinOp cmp (Ident var) bound
...@@ -179,19 +182,32 @@ convertStmt (Case unique kw expr cases) = do ...@@ -179,19 +182,32 @@ convertStmt (Case unique kw expr cases) = do
convertStmt (For convertStmt (For
(inits @ (SimpleLoopInits _ _ var1 _)) (inits @ (SimpleLoopInits _ _ var1 _))
(comp @ (SimpleLoopGuard _ var2 _)) (comp @ (SimpleLoopGuard _ var2 _))
(incr @ (SimpleLoopIncrs var3 _ _)) (incr @ (SimpleLoopIncrs var3 _ _)) stmt) =
stmt) = convertLoop localInfo loop comp incr stmt
if var1 /= var2 || var2 /= var3 where
then convertLoop False loop comp stmt loop c i s = For inits c i s
else convertLoop True loop comp stmt localInfo = if var1 /= var2 || var2 /= var3
where loop c s = For inits c incr s 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) = convertStmt (For inits comp incr stmt) =
convertLoop False loop comp stmt convertLoop Nothing loop comp incr stmt
where loop c s = For inits c incr s where loop c i s = For inits c i s
convertStmt (While comp stmt) = 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) = convertStmt (DoWhile comp stmt) =
convertLoop False DoWhile comp stmt convertLoop Nothing loop comp [] stmt
where loop c _ s = DoWhile c s
convertStmt (Continue) = do convertStmt (Continue) = do
loopDepth <- gets sLoopDepth loopDepth <- gets sLoopDepth
...@@ -255,8 +271,11 @@ convertSubStmt stmt = do ...@@ -255,8 +271,11 @@ convertSubStmt stmt = do
put origState put origState
return (stmt', hasJump) return (stmt', hasJump)
convertLoop :: Bool -> (Expr -> Stmt -> Stmt) -> Expr -> Stmt -> State Info Stmt type Incr = (LHS, AsgnOp, Expr)
convertLoop local loop comp stmt = do
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 -- save the loop state and increment loop depth
Info { sLoopDepth = origLoopDepth, sHasJump = origHasJump } <- get Info { sLoopDepth = origLoopDepth, sHasJump = origHasJump } <- get
assertMsg (not origHasJump) "has jump invariant failed" assertMsg (not origHasJump) "has jump invariant failed"
...@@ -268,13 +287,26 @@ convertLoop local loop comp stmt = do ...@@ -268,13 +287,26 @@ convertLoop local loop comp stmt = do
assertMsg (origLoopDepth + 1 == afterLoopDepth) "loop depth invariant failed" assertMsg (origLoopDepth + 1 == afterLoopDepth) "loop depth invariant failed"
modify $ \s -> s { sLoopDepth = origLoopDepth } 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 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 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 "" [] $ let body = Block Seq "" [] $
[ asgn jumpState jsNone [ asgn jumpState jsNone
, stmt' , 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 jsStackIdent = jumpState ++ "_" ++ show origLoopDepth
let jsStackDecl = Variable Local jumpStateType jsStackIdent [] let jsStackDecl = Variable Local jumpStateType jsStackIdent []
(Ident jumpState) (Ident jumpState)
...@@ -289,19 +321,36 @@ convertLoop local loop comp stmt = do ...@@ -289,19 +321,36 @@ convertLoop local loop comp stmt = do
return $ return $
if not afterHasJump then if not afterHasJump then
loop comp stmt' loop comp incr stmt'
else if origLoopDepth == 0 then else if origLoopDepth == 0 then
Block Seq "" [] Block Seq "" [ breakVarDecl ]
[ loop comp' body' [ loop comp' incr' body'
, pushBreakVar
, jsCheckReturn , jsCheckReturn
] ]
else else
Block Seq "" Block Seq ""
[ jsStackDecl ] [ breakVarDecl, jsStackDecl ]
[ loop comp' body' [ loop comp' incr' body'
, pushBreakVar
, jsStackRestore , 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 :: Type
jumpStateType = IntegerVector TBit Unspecified [(RawNum 0, RawNum 1)] jumpStateType = IntegerVector TBit Unspecified [(RawNum 0, RawNum 1)]
......
...@@ -8,8 +8,49 @@ module top; ...@@ -8,8 +8,49 @@ module top;
f = f * 2; f = f * 2;
end end
endfunction 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; integer i;
initial 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("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 endmodule
...@@ -6,8 +6,41 @@ module top; ...@@ -6,8 +6,41 @@ module top;
else else
f = 2 ** inp; f = 2 ** inp;
endfunction 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; integer i;
initial 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("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 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