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 =
++ " is not an integer"
convertCastM size value signed = do
value' <- traverseExprM value
useFn <- embedScopes canUseCastFn size
if useFn then do
sizeUsesLocalVars <- embedScopes usesLocalVars size
inProcedure <- withinProcedureM
if not sizeUsesLocalVars || not inProcedure then do
let name = castFnName size signed
let item = castFn name size signed
if sizeUsesLocalVars
then do
details <- lookupLocalIdentM name
when (details == Nothing) $
injectItem $ castFn name size signed
when (details == Nothing) (injectItem item)
else do
details <- lookupElemM name
when (details == Nothing) (injectTopItem item)
return $ Call (Ident name) (Args [value'] [])
else do
name <- castDeclName 0
......@@ -131,16 +137,19 @@ convertCastM size value signed = do
injectDecl $ castDecl useVar name value' size signed
return $ Ident name
-- checks if a cast size can be hoisted to a cast function
canUseCastFn :: Scopes a -> Expr -> Bool
canUseCastFn scopes size =
not (inProcedure && anyNonLocal)
-- checks if a cast size references any vars not defined at the top level scope
usesLocalVars :: Scopes a -> Expr -> Bool
usesLocalVars scopes =
getAny . execWriter . collectNestedExprsM collectLocalVarsM
where
inProcedure = withinProcedure scopes
anyNonLocal = getAny $ execWriter $
collectNestedExprsM collectNonLocalExprM size
collectNonLocalExprM :: Expr -> Writer Any ()
collectNonLocalExprM expr =
collectLocalVarsM :: Expr -> Writer Any ()
collectLocalVarsM expr@(Ident x) =
if isLoopVar scopes x
then tell $ Any True
else resolve expr
collectLocalVarsM expr = resolve expr
resolve :: Expr -> Writer Any ()
resolve expr =
case lookupElem scopes expr of
Nothing -> return ()
Just ([_, _], _, _) -> return ()
......
......@@ -38,6 +38,7 @@ module Convert.Scoper
, scopeType
, insertElem
, injectItem
, injectTopItem
, injectDecl
, lookupElem
, lookupElemM
......@@ -63,6 +64,7 @@ module Convert.Scoper
import Control.Monad.State.Strict
import Data.Functor.Identity (runIdentity)
import Data.List (partition)
import Data.Maybe (isNothing)
import qualified Data.Map.Strict as Map
......@@ -97,7 +99,7 @@ data Scopes a = Scopes
{ sCurrent :: [Tier]
, sMapping :: Mapping a
, sProcedureLoc :: [Access]
, sInjectedItems :: [ModuleItem]
, sInjectedItems :: [(Bool, ModuleItem)]
, sInjectedDecls :: [Decl]
} deriving Show
......@@ -225,7 +227,11 @@ insertElem key element = do
injectItem :: Monad m => ModuleItem -> ScoperT a m ()
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 decl =
......@@ -233,10 +239,13 @@ injectDecl decl =
consumeInjectedItems :: Monad m => ScoperT a m [ModuleItem]
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) $
modify' $ \s -> s { sInjectedItems = [] }
return $ reverse injected
modify' $ \s -> s { sInjectedItems = remaining }
return $ reverse $ map snd $ injected
consumeInjectedDecls :: Monad m => ScoperT a m [Decl]
consumeInjectedDecls = do
......@@ -517,7 +526,7 @@ scopeModuleItemT declMapper moduleItemMapper genItemMapper stmtMapper =
exitProcedure
return $ Final stmt'
fullModuleItemMapper (Generate genItems) =
mapM fullGenItemMapper genItems >>= return . Generate
fullGenItemBlockMapper genItems >>= return . Generate
fullModuleItemMapper (MIAttr attr item) =
fullModuleItemMapper item >>= return . MIAttr attr
fullModuleItemMapper item = moduleItemMapper item
......@@ -526,43 +535,48 @@ scopeModuleItemT declMapper moduleItemMapper genItemMapper stmtMapper =
fullGenItemMapper genItem = do
genItem' <- genItemMapper genItem
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
then scopeGenItemMapper genItem'
then return [genItem']
else do
injected' <- mapM fullModuleItemMapper injected
genItem'' <- scopeGenItemMapper genItem'
let genItems = map GenModuleItem injected' ++ [genItem'']
-- flattened during traversal
return $ GenModuleItem $ Generate genItems
return $ map GenModuleItem injected' ++ [genItem']
-- enters and exits generate block scopes as appropriate
scopeGenItemMapper :: GenItem -> ScoperT a m GenItem
scopeGenItemMapper (GenFor _ _ _ GenNull) = return GenNull
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'
scopeGenItemMapper (GenIf cond thenItem elseItem) = do
thenItem' <- scopeGenItemBranchMapper "" thenItem
elseItem' <- scopeGenItemBranchMapper "" elseItem
thenItem' <- fullGenItemMapper thenItem
elseItem' <- fullGenItemMapper elseItem
return $ GenIf cond thenItem' elseItem'
scopeGenItemMapper (GenBlock name genItems) = do
enterScope name ""
genItems' <- mapM fullGenItemMapper genItems
genItems' <- fullGenItemBlockMapper genItems
exitScope
return $ GenBlock name genItems'
scopeGenItemMapper (GenModuleItem moduleItem) =
wrappedModuleItemMapper moduleItem >>= return . GenModuleItem
scopeGenItemMapper genItem =
scopeGenItemMapper genItem@GenCase{} =
traverseSinglyNestedGenItemsM fullGenItemMapper genItem
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'
scopeGenItemMapper GenNull = return GenNull
partScoper
:: 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;
generate
for (genvar i = 1; i < 5; ++i) begin
localparam A = $unsigned(i'(1'sb1));
localparam B = $unsigned((i + 5)'(1'sb1));
initial begin
integer x, y;
x = $unsigned(i'(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
for (genvar j = 3; j < 6; ++j) begin
localparam C = $unsigned((i * j)'(1'sb1));
initial begin
integer x;
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
......
......@@ -2,17 +2,20 @@ module top;
generate
genvar i, j;
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
integer x, y;
x = $unsigned(cast_i(1'sb1));
y = (1 << (i + 5)) - 1;
$display("%0d %b %b", i, x, y);
$display("%0d %b %b %b %b", i, x, y, A, B);
end
for (j = 3; j < 6; j = j + 1) begin
localparam [i * j - 1:0] C = 1'sb1;
initial begin : bar
integer x;
x = (1 << (i * j)) - 1;
$display("%0d %0d %b", i, j, x);
$display("%0d %0d %b %b", i, j, x, C);
end
end
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