Commit 16a13ee9 by Zachary Snow

fix cascaded generate block cast and scope resolution

- scoper item injection can no longer affect generate scoping
- cast conversion injects functions into the top level when possible
- cast conversion considers loop variables to be local
- `else if` generate blocks are still scopes at the current level
parent eda9a34a
...@@ -117,12 +117,18 @@ convertCastM (Number size) (Number value) signed = ...@@ -117,12 +117,18 @@ convertCastM (Number size) (Number value) signed =
++ " is not an integer" ++ " is not an integer"
convertCastM size value signed = do convertCastM size value signed = do
value' <- traverseExprM value value' <- traverseExprM value
useFn <- embedScopes canUseCastFn size sizeUsesLocalVars <- embedScopes usesLocalVars size
if useFn then do inProcedure <- withinProcedureM
if not sizeUsesLocalVars || not inProcedure then do
let name = castFnName size signed let name = castFnName size signed
let item = castFn name size signed
if sizeUsesLocalVars
then do
details <- lookupLocalIdentM name details <- lookupLocalIdentM name
when (details == Nothing) $ when (details == Nothing) (injectItem item)
injectItem $ castFn name size signed else do
details <- lookupElemM name
when (details == Nothing) (injectTopItem item)
return $ Call (Ident name) (Args [value'] []) return $ Call (Ident name) (Args [value'] [])
else do else do
name <- castDeclName 0 name <- castDeclName 0
...@@ -131,16 +137,19 @@ convertCastM size value signed = do ...@@ -131,16 +137,19 @@ convertCastM size value signed = do
injectDecl $ castDecl useVar name value' size signed injectDecl $ castDecl useVar name value' size signed
return $ Ident name return $ Ident name
-- checks if a cast size can be hoisted to a cast function -- checks if a cast size references any vars not defined at the top level scope
canUseCastFn :: Scopes a -> Expr -> Bool usesLocalVars :: Scopes a -> Expr -> Bool
canUseCastFn scopes size = usesLocalVars scopes =
not (inProcedure && anyNonLocal) getAny . execWriter . collectNestedExprsM collectLocalVarsM
where where
inProcedure = withinProcedure scopes collectLocalVarsM :: Expr -> Writer Any ()
anyNonLocal = getAny $ execWriter $ collectLocalVarsM expr@(Ident x) =
collectNestedExprsM collectNonLocalExprM size if isLoopVar scopes x
collectNonLocalExprM :: Expr -> Writer Any () then tell $ Any True
collectNonLocalExprM expr = else resolve expr
collectLocalVarsM expr = resolve expr
resolve :: Expr -> Writer Any ()
resolve expr =
case lookupElem scopes expr of case lookupElem scopes expr of
Nothing -> return () Nothing -> return ()
Just ([_, _], _, _) -> return () Just ([_, _], _, _) -> return ()
......
...@@ -38,6 +38,7 @@ module Convert.Scoper ...@@ -38,6 +38,7 @@ module Convert.Scoper
, scopeType , scopeType
, insertElem , insertElem
, injectItem , injectItem
, injectTopItem
, injectDecl , injectDecl
, lookupElem , lookupElem
, lookupElemM , lookupElemM
...@@ -63,6 +64,7 @@ module Convert.Scoper ...@@ -63,6 +64,7 @@ module Convert.Scoper
import Control.Monad.State.Strict import Control.Monad.State.Strict
import Data.Functor.Identity (runIdentity) import Data.Functor.Identity (runIdentity)
import Data.List (partition)
import Data.Maybe (isNothing) import Data.Maybe (isNothing)
import qualified Data.Map.Strict as Map import qualified Data.Map.Strict as Map
...@@ -97,7 +99,7 @@ data Scopes a = Scopes ...@@ -97,7 +99,7 @@ data Scopes a = Scopes
{ sCurrent :: [Tier] { sCurrent :: [Tier]
, sMapping :: Mapping a , sMapping :: Mapping a
, sProcedureLoc :: [Access] , sProcedureLoc :: [Access]
, sInjectedItems :: [ModuleItem] , sInjectedItems :: [(Bool, ModuleItem)]
, sInjectedDecls :: [Decl] , sInjectedDecls :: [Decl]
} deriving Show } deriving Show
...@@ -225,7 +227,11 @@ insertElem key element = do ...@@ -225,7 +227,11 @@ insertElem key element = do
injectItem :: Monad m => ModuleItem -> ScoperT a m () injectItem :: Monad m => ModuleItem -> ScoperT a m ()
injectItem item = injectItem item =
modify' $ \s -> s { sInjectedItems = item : sInjectedItems s } modify' $ \s -> s { sInjectedItems = (True, item) : sInjectedItems s }
injectTopItem :: Monad m => ModuleItem -> ScoperT a m ()
injectTopItem item =
modify' $ \s -> s { sInjectedItems = (False, item) : sInjectedItems s }
injectDecl :: Monad m => Decl -> ScoperT a m () injectDecl :: Monad m => Decl -> ScoperT a m ()
injectDecl decl = injectDecl decl =
...@@ -233,10 +239,13 @@ injectDecl decl = ...@@ -233,10 +239,13 @@ injectDecl decl =
consumeInjectedItems :: Monad m => ScoperT a m [ModuleItem] consumeInjectedItems :: Monad m => ScoperT a m [ModuleItem]
consumeInjectedItems = do consumeInjectedItems = do
injected <- gets sInjectedItems -- only pull out top items if in the top scope
inTopLevelScope <- gets $ (== 1) . length . sCurrent
let op = if inTopLevelScope then const True else fst
(injected, remaining) <- gets $ partition op . sInjectedItems
when (not $ null injected) $ when (not $ null injected) $
modify' $ \s -> s { sInjectedItems = [] } modify' $ \s -> s { sInjectedItems = remaining }
return $ reverse injected return $ reverse $ map snd $ injected
consumeInjectedDecls :: Monad m => ScoperT a m [Decl] consumeInjectedDecls :: Monad m => ScoperT a m [Decl]
consumeInjectedDecls = do consumeInjectedDecls = do
...@@ -517,7 +526,7 @@ scopeModuleItemT declMapper moduleItemMapper genItemMapper stmtMapper = ...@@ -517,7 +526,7 @@ scopeModuleItemT declMapper moduleItemMapper genItemMapper stmtMapper =
exitProcedure exitProcedure
return $ Final stmt' return $ Final stmt'
fullModuleItemMapper (Generate genItems) = fullModuleItemMapper (Generate genItems) =
mapM fullGenItemMapper genItems >>= return . Generate fullGenItemBlockMapper genItems >>= return . Generate
fullModuleItemMapper (MIAttr attr item) = fullModuleItemMapper (MIAttr attr item) =
fullModuleItemMapper item >>= return . MIAttr attr fullModuleItemMapper item >>= return . MIAttr attr
fullModuleItemMapper item = moduleItemMapper item fullModuleItemMapper item = moduleItemMapper item
...@@ -526,43 +535,48 @@ scopeModuleItemT declMapper moduleItemMapper genItemMapper stmtMapper = ...@@ -526,43 +535,48 @@ scopeModuleItemT declMapper moduleItemMapper genItemMapper stmtMapper =
fullGenItemMapper genItem = do fullGenItemMapper genItem = do
genItem' <- genItemMapper genItem genItem' <- genItemMapper genItem
injected <- consumeInjectedItems injected <- consumeInjectedItems
genItem'' <- scopeGenItemMapper genItem'
mapM_ injectItem injected -- defer until enclosing block
return genItem''
-- akin to fullGenItemMapper, but for lists of generate items, and
-- allowing module items to be injected in the middle of the list
fullGenItemBlockMapper :: [GenItem] -> ScoperT a m [GenItem]
fullGenItemBlockMapper = fmap concat . mapM genblkStep
genblkStep :: GenItem -> ScoperT a m [GenItem]
genblkStep genItem = do
genItem' <- fullGenItemMapper genItem
injected <- consumeInjectedItems
if null injected if null injected
then scopeGenItemMapper genItem' then return [genItem']
else do else do
injected' <- mapM fullModuleItemMapper injected injected' <- mapM fullModuleItemMapper injected
genItem'' <- scopeGenItemMapper genItem' return $ map GenModuleItem injected' ++ [genItem']
let genItems = map GenModuleItem injected' ++ [genItem'']
-- flattened during traversal -- enters and exits generate block scopes as appropriate
return $ GenModuleItem $ Generate genItems
scopeGenItemMapper :: GenItem -> ScoperT a m GenItem scopeGenItemMapper :: GenItem -> ScoperT a m GenItem
scopeGenItemMapper (GenFor _ _ _ GenNull) = return GenNull
scopeGenItemMapper (GenFor (index, a) b c genItem) = do scopeGenItemMapper (GenFor (index, a) b c genItem) = do
genItem' <- scopeGenItemBranchMapper index genItem let GenBlock name genItems = genItem
enterScope name index
genItems' <- fullGenItemBlockMapper genItems
exitScope
let genItem' = GenBlock name genItems'
return $ GenFor (index, a) b c genItem' return $ GenFor (index, a) b c genItem'
scopeGenItemMapper (GenIf cond thenItem elseItem) = do scopeGenItemMapper (GenIf cond thenItem elseItem) = do
thenItem' <- scopeGenItemBranchMapper "" thenItem thenItem' <- fullGenItemMapper thenItem
elseItem' <- scopeGenItemBranchMapper "" elseItem elseItem' <- fullGenItemMapper elseItem
return $ GenIf cond thenItem' elseItem' return $ GenIf cond thenItem' elseItem'
scopeGenItemMapper (GenBlock name genItems) = do scopeGenItemMapper (GenBlock name genItems) = do
enterScope name "" enterScope name ""
genItems' <- mapM fullGenItemMapper genItems genItems' <- fullGenItemBlockMapper genItems
exitScope exitScope
return $ GenBlock name genItems' return $ GenBlock name genItems'
scopeGenItemMapper (GenModuleItem moduleItem) = scopeGenItemMapper (GenModuleItem moduleItem) =
wrappedModuleItemMapper moduleItem >>= return . GenModuleItem wrappedModuleItemMapper moduleItem >>= return . GenModuleItem
scopeGenItemMapper genItem = scopeGenItemMapper genItem@GenCase{} =
traverseSinglyNestedGenItemsM fullGenItemMapper genItem traverseSinglyNestedGenItemsM fullGenItemMapper genItem
scopeGenItemMapper GenNull = return GenNull
scopeGenItemBranchMapper :: Identifier -> GenItem -> ScoperT a m GenItem
scopeGenItemBranchMapper index (GenBlock name genItems) = do
enterScope name index
genItems' <- mapM fullGenItemMapper genItems
exitScope
return $ GenBlock name genItems'
scopeGenItemBranchMapper index genItem = do
enterScope "" index
genItem' <- fullGenItemMapper genItem
exitScope
return genItem'
partScoper partScoper
:: MapperM (Scoper a) Decl :: MapperM (Scoper a) Decl
......
`ifdef REF
`define CHECK(N) (P & (1 << (Z+N+1) - 1))
`else
`define CHECK(N) ((Z+N+1)'(P) & (1 << (Z+N+1) - 1))
`endif
`define PRINT(N) initial #P $display(`"%b bit N is set`", P);
module mod;
parameter unsigned P = 1;
parameter Z = 0;
if (!Z) begin : blk1
if (`CHECK(0)) `PRINT(0)
else if (`CHECK(1)) `PRINT(1)
else if (`CHECK(2)) `PRINT(2)
end
if (!Z) begin : blk2
genvar i;
if (`CHECK(3))
`PRINT(3)
else
for (i = 1; i == 1 && `CHECK(4); i = i + 1)
`PRINT(4)
end
if (!Z) begin : blk3
wire signed x = 1;
`ifdef REF
wire [P - 1:0] tmp = x;
wire [7:0] y = tmp;
`else
wire [7:0] y = $unsigned(P'(x));
`endif
end
wire [7:0] x = blk3.y;
initial #P $display("%b x = %b", P, x);
endmodule
`define REF
`include "cast_top_item.sv"
module top;
genvar i;
generate
for (i = 0; i < 32; i = i + 1)
mod #(i) m();
endgenerate
endmodule
module top; module top;
generate generate
for (genvar i = 1; i < 5; ++i) begin for (genvar i = 1; i < 5; ++i) begin
localparam A = $unsigned(i'(1'sb1));
localparam B = $unsigned((i + 5)'(1'sb1));
initial begin initial begin
integer x, y; integer x, y;
x = $unsigned(i'(1'sb1)); x = $unsigned(i'(1'sb1));
y = $unsigned((i + 5)'(1'sb1)); y = $unsigned((i + 5)'(1'sb1));
$display("%0d %b %b", i, x, y); $display("%0d %b %b %b %b", i, x, y, A, B);
end end
for (genvar j = 3; j < 6; ++j) begin for (genvar j = 3; j < 6; ++j) begin
localparam C = $unsigned((i * j)'(1'sb1));
initial begin initial begin
integer x; integer x;
x = $unsigned((i * j)'(1'sb1)); x = $unsigned((i * j)'(1'sb1));
$display("%0d %0d %b", i, j, x); $display("%0d %0d %b %b", i, j, x, C);
end end
end end
end end
......
...@@ -2,17 +2,20 @@ module top; ...@@ -2,17 +2,20 @@ module top;
generate generate
genvar i, j; genvar i, j;
for (i = 1; i < 5; i = i + 1) begin for (i = 1; i < 5; i = i + 1) begin
localparam [i - 1:0] A = 1'sb1;
localparam [i + 4:0] B = 1'sb1;
initial begin : foo initial begin : foo
integer x, y; integer x, y;
x = $unsigned(cast_i(1'sb1)); x = $unsigned(cast_i(1'sb1));
y = (1 << (i + 5)) - 1; y = (1 << (i + 5)) - 1;
$display("%0d %b %b", i, x, y); $display("%0d %b %b %b %b", i, x, y, A, B);
end end
for (j = 3; j < 6; j = j + 1) begin for (j = 3; j < 6; j = j + 1) begin
localparam [i * j - 1:0] C = 1'sb1;
initial begin : bar initial begin : bar
integer x; integer x;
x = (1 << (i * j)) - 1; x = (1 << (i * j)) - 1;
$display("%0d %0d %b", i, j, x); $display("%0d %0d %b %b", i, j, x, C);
end end
end end
function signed [i-1:0] cast_i; function signed [i-1:0] cast_i;
......
module mod(
output wire [31:0] out
);
parameter P = 0;
if (P == 1) begin : blk1
wire w [2];
end
else if (P == 2) begin : blk2
wire x [3];
end
else if (P == 3) begin : blk3
wire y [5];
end
else begin : blk4
wire z [7];
end
if (P == 1)
assign out = $bits(blk1.w);
else if (P == 2)
assign out = $bits(blk2.x);
else if (P == 3)
assign out = $bits(blk3.y);
else
assign out = $bits(blk4.z);
endmodule
module mod(
output wire [31:0] out
);
parameter P = 0;
if (P == 1)
assign out = 2;
else if (P == 2)
assign out = 3;
else if (P == 3)
assign out = 5;
else
assign out = 7;
endmodule
module top;
wire [31:0] out1, out2, out3, out4;
mod #(1) m1(out1);
mod #(2) m2(out2);
mod #(3) m3(out3);
mod #(4) m4(out4);
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