From fabab15e38f752bc98008a350e9817819ed0801a Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Wed, 3 Dec 2025 17:33:41 +0100 Subject: Restore suffixes sharing in *FromLinear Thanks Mikolaj for spotting it's broken --- src/Data/Array/Nested/Mixed/Shape/Internal.hs | 49 +++++++++++++++------------ 1 file changed, 28 insertions(+), 21 deletions(-) (limited to 'src/Data/Array/Nested/Mixed/Shape') diff --git a/src/Data/Array/Nested/Mixed/Shape/Internal.hs b/src/Data/Array/Nested/Mixed/Shape/Internal.hs index cf44522..9997b0f 100644 --- a/src/Data/Array/Nested/Mixed/Shape/Internal.hs +++ b/src/Data/Array/Nested/Mixed/Shape/Internal.hs @@ -19,32 +19,39 @@ ixFromLinearStub fname' ishty ixty zshC consshC ixz ixcons shtolist = do typesig <- [t| forall i sh. Num i => $ishty sh -> Int -> $ixty sh i |] locals <- [d| - fromLin :: Num i => $ishty sh -> [Int] -> Int -> $ixty sh i - fromLin $zshC _ !_ = $ixz - fromLin ($(consshC wildP (varP (mkName "sh'")))) (suff : suffs) i = - let (q, r) = i `quotRem` suff -- suff == shrSize sh' - in $ixcons (fromIntegral q) (fromLin sh' suffs r) - fromLin _ _ _ = error "impossible" - - {-# NOINLINE outrange #-} - outrange :: $ishty sh -> Int -> a - outrange sh i = error $ fname' ++ ": out of range (" ++ show i ++ - " in array of shape " ++ show sh ++ ")" |] + -- Unfold first iteration of fromLin to do the range check. + -- Don't inline because if this is inlined, GHC seems to stop sharing + -- 'suffixes' over multiple calls, which breaks performance in sh*Enum. + {-# NOINLINE fromLin0 #-} + fromLin0 :: Num i => $ishty sh -> [Int] -> Int -> $ixty sh i + fromLin0 sh suffixes i = + if i < 0 then outrange sh i else + case (sh, suffixes) of + ($zshC, _) | i > 0 -> outrange sh i + | otherwise -> $ixz + ($(consshC (varP (mkName "n")) (varP (mkName "sh'"))), suff : suffs) -> + let (q, r) = i `quotRem` suff + in if q >= n then outrange sh i else + $ixcons (fromIntegral q) (fromLin sh' suffs r) + _ -> error "impossible" + + fromLin :: Num i => $ishty sh -> [Int] -> Int -> $ixty sh i + fromLin $zshC _ !_ = $ixz + fromLin ($(consshC wildP (varP (mkName "sh'")))) (suff : suffs) i = + let (q, r) = i `quotRem` suff -- suff == shrSize sh' + in $ixcons (fromIntegral q) (fromLin sh' suffs r) + fromLin _ _ _ = error "impossible" + + {-# NOINLINE outrange #-} + outrange :: $ishty sh -> Int -> a + outrange sh i = error $ fname' ++ ": out of range (" ++ show i ++ + " in array of shape " ++ show sh ++ ")" |] body <- [| \sh -> -- give this function arity 1 so that 'suffixes' is shared when -- it's called many times let suffixes = drop 1 (scanr (*) 1 ($shtolist sh)) - in \i -> - if i < 0 then outrange sh i else - case (sh, suffixes) of -- unfold first iteration of fromLin to do the range check - ($zshC, _) | i > 0 -> outrange sh i - | otherwise -> $ixz - ($(consshC (varP (mkName "n")) (varP (mkName "sh'"))), suff : suffs) -> - let (q, r) = i `quotRem` suff - in if q >= n then outrange sh i else - $ixcons (fromIntegral q) (fromLin sh' suffs r) - _ -> error "impossible" |] + in fromLin0 sh suffixes |] return [SigD fname typesig ,FunD fname [Clause [] (NormalB body) locals]] -- cgit v1.2.3-70-g09d2