Skip to content

Commit 685da60

Browse files
Prevent space leaks in zip family
In the multi-map implementation, each part of the tuple will reference the original input if left unevaluated. In case of `Signal`s, this can cause the complete simulation to build up in memory. Fixes #3038
1 parent 80b4a38 commit 685da60

File tree

2 files changed

+80
-31
lines changed

2 files changed

+80
-31
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
FIXED: The `unzip` family no longer retains a reference to the original input for every (unevaluated) part of the output tuple. This can help to prevent space leaks. See [#3038](https://github.com/clash-lang/clash-compiler/issues/3038).

clash-prelude/src/Clash/Sized/Vector.hs

Lines changed: 79 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1424,7 +1424,15 @@ zip7 = zipWith7 (,,,,,,)
14241424
-- >>> unzip ((1,4):>(2,3):>(3,2):>(4,1):>Nil)
14251425
-- (1 :> 2 :> 3 :> 4 :> Nil,4 :> 3 :> 2 :> 1 :> Nil)
14261426
unzip :: Vec n (a,b) -> (Vec n a, Vec n b)
1427-
unzip xs = (map fst xs, map snd xs)
1427+
unzip xs
1428+
| clashSimulation = unzipSim xs
1429+
| otherwise = (map fst xs, map snd xs)
1430+
where
1431+
unzipSim :: Vec m (a,b) -> (Vec m a, Vec m b)
1432+
unzipSim Nil = (Nil, Nil)
1433+
unzipSim (~(a,b) `Cons` rest) =
1434+
let (as, bs) = unzipSim rest
1435+
in (a `Cons` as, b `Cons` bs)
14281436
{-# INLINE unzip #-}
14291437

14301438
-- | 'unzip3' transforms a vector of triplets into a vector of first components,
@@ -1433,60 +1441,100 @@ unzip xs = (map fst xs, map snd xs)
14331441
-- >>> unzip3 ((1,4,5):>(2,3,6):>(3,2,7):>(4,1,8):>Nil)
14341442
-- (1 :> 2 :> 3 :> 4 :> Nil,4 :> 3 :> 2 :> 1 :> Nil,5 :> 6 :> 7 :> 8 :> Nil)
14351443
unzip3 :: Vec n (a,b,c) -> (Vec n a, Vec n b, Vec n c)
1436-
unzip3 xs = ( map (\(x,_,_) -> x) xs
1437-
, map (\(_,y,_) -> y) xs
1438-
, map (\(_,_,z) -> z) xs
1439-
)
1444+
unzip3 xs
1445+
| clashSimulation = unzip3Sim xs
1446+
| otherwise = ( map (\(x,_,_) -> x) xs
1447+
, map (\(_,y,_) -> y) xs
1448+
, map (\(_,_,z) -> z) xs
1449+
)
1450+
where
1451+
unzip3Sim :: Vec m (a,b,c) -> (Vec m a, Vec m b, Vec m c)
1452+
unzip3Sim Nil = (Nil, Nil, Nil)
1453+
unzip3Sim (~(a,b,c) `Cons` rest) =
1454+
let (as, bs, cs) = unzip3Sim rest
1455+
in (a `Cons` as, b `Cons` bs, c `Cons` cs)
14401456
{-# INLINE unzip3 #-}
14411457

14421458
-- | 'unzip4' takes a vector of quadruples and returns four vectors, analogous
14431459
-- to 'unzip'.
14441460
unzip4 :: Vec n (a,b,c,d) -> (Vec n a, Vec n b, Vec n c, Vec n d)
1445-
unzip4 xs = ( map (\(w,_,_,_) -> w) xs
1446-
, map (\(_,x,_,_) -> x) xs
1447-
, map (\(_,_,y,_) -> y) xs
1448-
, map (\(_,_,_,z) -> z) xs
1449-
)
1461+
unzip4 xs
1462+
| clashSimulation = unzip4Sim xs
1463+
| otherwise = ( map (\(w,_,_,_) -> w) xs
1464+
, map (\(_,x,_,_) -> x) xs
1465+
, map (\(_,_,y,_) -> y) xs
1466+
, map (\(_,_,_,z) -> z) xs
1467+
)
1468+
where
1469+
unzip4Sim :: Vec m (a,b,c,d) -> (Vec m a, Vec m b, Vec m c, Vec m d)
1470+
unzip4Sim Nil = (Nil, Nil, Nil, Nil)
1471+
unzip4Sim (~(a,b,c,d) `Cons` rest) =
1472+
let (as, bs, cs, ds) = unzip4Sim rest
1473+
in (a `Cons` as, b `Cons` bs, c `Cons` cs, d `Cons` ds)
14501474
{-# INLINE unzip4 #-}
14511475

14521476
-- | 'unzip5' takes a vector of five-tuples and returns five vectors, analogous
14531477
-- to 'unzip'.
14541478
unzip5 :: Vec n (a,b,c,d,e) -> (Vec n a, Vec n b, Vec n c, Vec n d, Vec n e)
1455-
unzip5 xs = ( map (\(v,_,_,_,_) -> v) xs
1456-
, map (\(_,w,_,_,_) -> w) xs
1457-
, map (\(_,_,x,_,_) -> x) xs
1458-
, map (\(_,_,_,y,_) -> y) xs
1459-
, map (\(_,_,_,_,z) -> z) xs
1460-
)
1479+
unzip5 xs
1480+
| clashSimulation = unzip5Sim xs
1481+
| otherwise = ( map (\(v,_,_,_,_) -> v) xs
1482+
, map (\(_,w,_,_,_) -> w) xs
1483+
, map (\(_,_,x,_,_) -> x) xs
1484+
, map (\(_,_,_,y,_) -> y) xs
1485+
, map (\(_,_,_,_,z) -> z) xs
1486+
)
1487+
where
1488+
unzip5Sim :: Vec m (a,b,c,d,e) -> (Vec m a, Vec m b, Vec m c, Vec m d, Vec m e)
1489+
unzip5Sim Nil = (Nil, Nil, Nil, Nil, Nil)
1490+
unzip5Sim (~(a,b,c,d,e) `Cons` rest) =
1491+
let (as, bs, cs, ds, es) = unzip5Sim rest
1492+
in (a `Cons` as, b `Cons` bs, c `Cons` cs, d `Cons` ds, e `Cons` es)
14611493
{-# INLINE unzip5 #-}
14621494

14631495
-- | 'unzip6' takes a vector of six-tuples and returns six vectors, analogous
14641496
-- to 'unzip'.
14651497
unzip6
14661498
:: Vec n (a,b,c,d,e,f)
14671499
-> (Vec n a, Vec n b, Vec n c, Vec n d, Vec n e, Vec n f)
1468-
unzip6 xs = ( map (\(u,_,_,_,_,_) -> u) xs
1469-
, map (\(_,v,_,_,_,_) -> v) xs
1470-
, map (\(_,_,w,_,_,_) -> w) xs
1471-
, map (\(_,_,_,x,_,_) -> x) xs
1472-
, map (\(_,_,_,_,y,_) -> y) xs
1473-
, map (\(_,_,_,_,_,z) -> z) xs
1474-
)
1500+
unzip6 xs
1501+
| clashSimulation = unzip6Sim xs
1502+
| otherwise = ( map (\(u,_,_,_,_,_) -> u) xs
1503+
, map (\(_,v,_,_,_,_) -> v) xs
1504+
, map (\(_,_,w,_,_,_) -> w) xs
1505+
, map (\(_,_,_,x,_,_) -> x) xs
1506+
, map (\(_,_,_,_,y,_) -> y) xs
1507+
, map (\(_,_,_,_,_,z) -> z) xs
1508+
)
1509+
where
1510+
unzip6Sim :: Vec m (a,b,c,d,e,f) -> (Vec m a, Vec m b, Vec m c, Vec m d, Vec m e, Vec m f)
1511+
unzip6Sim Nil = (Nil, Nil, Nil, Nil, Nil, Nil)
1512+
unzip6Sim (~(a,b,c,d,e,f) `Cons` rest) =
1513+
let (as, bs, cs, ds, es, fs) = unzip6Sim rest
1514+
in (a `Cons` as, b `Cons` bs, c `Cons` cs, d `Cons` ds, e `Cons` es, f `Cons` fs)
14751515
{-# INLINE unzip6 #-}
14761516

14771517
-- | 'unzip7' takes a vector of seven-tuples and returns seven vectors, analogous
14781518
-- to 'unzip'.
14791519
unzip7
14801520
:: Vec n (a,b,c,d,e,f,g)
14811521
-> (Vec n a, Vec n b, Vec n c, Vec n d, Vec n e, Vec n f, Vec n g)
1482-
unzip7 xs = ( map (\(t,_,_,_,_,_,_) -> t) xs
1483-
, map (\(_,u,_,_,_,_,_) -> u) xs
1484-
, map (\(_,_,v,_,_,_,_) -> v) xs
1485-
, map (\(_,_,_,w,_,_,_) -> w) xs
1486-
, map (\(_,_,_,_,x,_,_) -> x) xs
1487-
, map (\(_,_,_,_,_,y,_) -> y) xs
1488-
, map (\(_,_,_,_,_,_,z) -> z) xs
1489-
)
1522+
unzip7 xs
1523+
| clashSimulation = unzip7Sim xs
1524+
| otherwise = ( map (\(t,_,_,_,_,_,_) -> t) xs
1525+
, map (\(_,u,_,_,_,_,_) -> u) xs
1526+
, map (\(_,_,v,_,_,_,_) -> v) xs
1527+
, map (\(_,_,_,w,_,_,_) -> w) xs
1528+
, map (\(_,_,_,_,x,_,_) -> x) xs
1529+
, map (\(_,_,_,_,_,y,_) -> y) xs
1530+
, map (\(_,_,_,_,_,_,z) -> z) xs
1531+
)
1532+
where
1533+
unzip7Sim :: Vec m (a,b,c,d,e,f,g) -> (Vec m a, Vec m b, Vec m c, Vec m d, Vec m e, Vec m f, Vec m g)
1534+
unzip7Sim Nil = (Nil, Nil, Nil, Nil, Nil, Nil, Nil)
1535+
unzip7Sim (~(a,b,c,d,e,f,g) `Cons` rest) =
1536+
let (as, bs, cs, ds, es, fs, gs) = unzip7Sim rest
1537+
in (a `Cons` as, b `Cons` bs, c `Cons` cs, d `Cons` ds, e `Cons` es, f `Cons` fs, g `Cons` gs)
14901538
{-# INLINE unzip7 #-}
14911539

14921540

0 commit comments

Comments
 (0)