[Git][ghc/ghc][wip/T22227] Loopification in OccurAnal
Sebastian Graf (@sgraf812)
gitlab at gitlab.haskell.org
Sat Oct 1 11:22:59 UTC 2022
Sebastian Graf pushed to branch wip/T22227 at Glasgow Haskell Compiler / GHC
Commits:
63c2f0df by Sebastian Graf at 2022-10-01T13:22:51+02:00
Loopification in OccurAnal
- - - - -
5 changed files:
- compiler/GHC/Core/Opt/OccurAnal.hs
- + testsuite/tests/simplCore/should_compile/T22227.hs
- + testsuite/tests/simplCore/should_compile/T22227.stderr
- testsuite/tests/simplCore/should_compile/all.T
- testsuite/tests/stranal/sigs/T5075.hs
Changes:
=====================================
compiler/GHC/Core/Opt/OccurAnal.hs
=====================================
@@ -58,7 +58,7 @@ import GHC.Utils.Trace
import GHC.Builtin.Names( runRWKey )
import GHC.Unit.Module( Module )
-import Data.List (mapAccumL, mapAccumR)
+import Data.List (mapAccumL, mapAccumR, find)
{-
************************************************************************
@@ -856,15 +856,31 @@ occAnalRec !_ lvl (AcyclicSCC (ND { nd_bndr = bndr, nd_rhs = rhs
-- See Note [Recursive bindings: the grand plan]
-- See Note [Loop breaking]
occAnalRec env lvl (CyclicSCC details_s) (WithUsageDetails body_uds binds)
- | not (any (`usedIn` body_uds) bndrs) -- NB: look at body_uds, not total_uds
+ | null used_bndrs
= WithUsageDetails body_uds binds -- See Note [Dead code]
+ | [loop_entry] <- used_bndrs
+ , let orig_occ = lookupDetails body_uds loop_entry
+ , NoTailCallInfo <- tailCallInfo orig_occ
+--- , case orig_occ of OneOcc{occ_in_lam=NotInsideLam}->False; _ -> True
+ , let unadj_uds = foldr (andUDs . nd_uds) emptyDetails details_s
+ , decideJoinPointHood lvl unadj_uds bndrs
+ , AlwaysTailCalled arity <- tailCallInfo $ lookupDetails unadj_uds loop_entry
+ , Just loop_nds <- find ((== loop_entry) . nd_bndr) details_s
+ , (!lam_bndrs,_) <- collectNBinders arity (nd_rhs loop_nds)
+ , let !loop_body_uds = mkOneOcc loop_entry IsInteresting arity
+ , WithUsageDetails new_rhs_uds loop_binds <- occAnalRec env lvl (CyclicSCC details_s) (WithUsageDetails loop_body_uds [])
+ , (body_uds',loop_entry') <- tagNonRecBinder lvl body_uds loop_entry
+ , let new_bind = NonRec loop_entry' (mkLams lam_bndrs (mkLets loop_binds (mkVarApps (Var loop_entry') lam_bndrs)))
+ = WithUsageDetails (markAllNonTail new_rhs_uds `andUDs` body_uds') (new_bind : binds)
+
| otherwise -- At this point we always build a single Rec
= -- pprTrace "occAnalRec" (ppr loop_breaker_nodes)
WithUsageDetails final_uds (Rec pairs : binds)
where
bndrs = map nd_bndr details_s
+ used_bndrs = filter (`usedIn` body_uds) bndrs -- NB: look at body_uds, not total_uds
all_simple = all nd_simple details_s
------------------------------
=====================================
testsuite/tests/simplCore/should_compile/T22227.hs
=====================================
@@ -0,0 +1,39 @@
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE UnboxedTuples #-}
+
+module Unboxed (test) where
+
+import GHC.Exts
+import GHC.IO
+
+data Step s a = Yield a s | Done
+
+uninitialised = undefined
+
+test :: Int# -> Int# -> Array# Double -> (# Int#, Int#, Array# Double #)
+test off n oldArr = runRW# $ \s0 ->
+ case newArray# n uninitialised s0
+ of { (# s1, newArr #) ->
+ let
+ step' i
+ | isTrue# (i >=# n) = Done
+ | otherwise =
+ let (# D# x #) = indexArray# oldArr (off +# i) in
+ if isTrue# (x >## 10.0##)
+ then Yield (D# x) (I# (i +# 1#))
+ else step' (i +# 1#)
+ loop i j s2 =
+ case step' i of
+ Yield x (I# s') ->
+ case writeArray# newArr j (x + 1) s2
+ of { s3 ->
+ loop s' (j +# 1#) s3
+ }
+ Done ->
+ case unsafeFreezeArray# newArr s2
+ of { (# s3, out #) ->
+ (# 0#, j, out #)
+ }
+ in
+ loop 0# 0# s1
+ }
=====================================
testsuite/tests/simplCore/should_compile/T22227.stderr
=====================================
@@ -0,0 +1,326 @@
+
+==================== Tidy Core ====================
+Result size of Tidy Core
+ = {terms: 213, types: 211, coercions: 4, joins: 5/5}
+
+-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
+lvl_rUP :: Addr#
+[GblId, Unf=OtherCon []]
+lvl_rUP = "undefined"#
+
+-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
+lvl1_rUQ :: [Char]
+[GblId]
+lvl1_rUQ = unpackCString# lvl_rUP
+
+-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
+Unboxed.$trModule4 :: Addr#
+[GblId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
+ WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 20 0}]
+Unboxed.$trModule4 = "main"#
+
+-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
+lvl2_rUR :: [Char]
+[GblId]
+lvl2_rUR = unpackCString# Unboxed.$trModule4
+
+-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
+Unboxed.$trModule2 :: Addr#
+[GblId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
+ WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 30 0}]
+Unboxed.$trModule2 = "Unboxed"#
+
+-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
+lvl3_rUS :: [Char]
+[GblId]
+lvl3_rUS = unpackCString# Unboxed.$trModule2
+
+-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
+lvl4_rUT :: Addr#
+[GblId, Unf=OtherCon []]
+lvl4_rUT = "T22227.hs"#
+
+-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
+lvl5_rUU :: [Char]
+[GblId]
+lvl5_rUU = unpackCString# lvl4_rUT
+
+-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
+lvl6_rUV :: Int
+[GblId, Unf=OtherCon []]
+lvl6_rUV = GHC.Types.I# 11#
+
+-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
+lvl7_rUW :: Int
+[GblId, Unf=OtherCon []]
+lvl7_rUW = GHC.Types.I# 17#
+
+-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
+lvl8_rUX :: Int
+[GblId, Unf=OtherCon []]
+lvl8_rUX = GHC.Types.I# 26#
+
+-- RHS size: {terms: 8, types: 0, coercions: 0, joins: 0/0}
+lvl9_rUY :: GHC.Stack.Types.SrcLoc
+[GblId, Unf=OtherCon []]
+lvl9_rUY
+ = GHC.Stack.Types.SrcLoc
+ lvl2_rUR lvl3_rUS lvl5_rUU lvl6_rUV lvl7_rUW lvl6_rUV lvl8_rUX
+
+-- RHS size: {terms: 4, types: 0, coercions: 0, joins: 0/0}
+lvl10_rUZ :: GHC.Stack.Types.CallStack
+[GblId, Unf=OtherCon []]
+lvl10_rUZ
+ = GHC.Stack.Types.PushCallStack
+ lvl1_rUQ lvl9_rUY GHC.Stack.Types.EmptyCallStack
+
+-- RHS size: {terms: 3, types: 3, coercions: 4, joins: 0/0}
+uninitialised :: forall {a}. a
+[GblId, Str=b, Cpr=b]
+uninitialised
+ = \ (@a_aCz) ->
+ undefined
+ @LiftedRep
+ @a_aCz
+ (lvl10_rUZ
+ `cast` (Sym (GHC.Classes.N:IP[0]
+ <"callStack">_N <GHC.Stack.Types.CallStack>_N)
+ :: GHC.Stack.Types.CallStack
+ ~R# (?callStack::GHC.Stack.Types.CallStack)))
+
+-- RHS size: {terms: 90, types: 151, coercions: 0, joins: 5/5}
+test
+ :: Int# -> Int# -> Array# Double -> (# Int#, Int#, Array# Double #)
+[GblId,
+ Arity=3,
+ Str=<L><L><L>,
+ Cpr=1,
+ Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
+ WorkFree=True, Expandable=True, Guidance=IF_ARGS [0 0 0] 137 0}]
+test
+ = \ (off_axL :: Int#)
+ (n_axM :: Int#)
+ (oldArr_axN :: Array# Double) ->
+ runRW#
+ @('TupleRep '[ 'IntRep, 'IntRep, UnliftedRep])
+ @(# Int#, Int#, Array# Double #)
+ (\ (s_sSR [OS=OneShot] :: State# RealWorld) ->
+ case newArray#
+ @'Lifted @Double @RealWorld n_axM (uninitialised @Double) s_sSR
+ of
+ { (# ipv_sSS, ipv1_sST #) ->
+ join {
+ exit_X0 [Dmd=SC(S,C(1,!P(L,L,L)))]
+ :: Int# -> State# RealWorld -> (# Int#, Int#, Array# Double #)
+ [LclId[JoinId(2)(Nothing)], Arity=2, Str=<L><L>]
+ exit_X0 (j_ay1 [OS=OneShot] :: Int#)
+ (s2_ay2 [OS=OneShot] :: State# RealWorld)
+ = case unsafeFreezeArray#
+ @'Lifted @RealWorld @Double ipv1_sST s2_ay2
+ of
+ { (# ipv2_sT8, ipv3_sT9 #) ->
+ (# 0#, j_ay1, ipv3_sT9 #)
+ } } in
+ joinrec {
+ loop_sTq [Occ=LoopBreaker, Dmd=SC(S,C(1,C(1,L)))]
+ :: Int#
+ -> Int# -> State# RealWorld -> (# Int#, Int#, Array# Double #)
+ [LclId[JoinId(3)(Nothing)],
+ Arity=3,
+ Str=<L><L><L>,
+ Unf=OtherCon []]
+ loop_sTq (i_ay0 :: Int#)
+ (j_ay1 :: Int#)
+ (s2_ay2 :: State# RealWorld)
+ = join {
+ exit1_X4 [Dmd=LC(S,C(1,!P(L,L,L)))]
+ :: Int# -> Double# -> (# Int#, Int#, Array# Double #)
+ [LclId[JoinId(2)(Nothing)], Arity=2, Str=<L><L>]
+ exit1_X4 (i1_X1 [OS=OneShot] :: Int#)
+ (x_aPv [OS=OneShot] :: Double#)
+ = case writeArray#
+ @'Lifted
+ @RealWorld
+ @Double
+ ipv1_sST
+ j_ay1
+ (GHC.Types.D# (+## x_aPv 1.0##))
+ s2_ay2
+ of s3_aAH
+ { __DEFAULT ->
+ jump loop_sTq (+# i1_X1 1#) (+# j_ay1 1#) s3_aAH
+ } } in
+ join {
+ $j_sTM [Dmd=L!P(L,L,L)] :: (# Int#, Int#, Array# Double #)
+ [LclId[JoinId(0)(Nothing)]]
+ $j_sTM = jump exit_X0 j_ay1 s2_ay2 } in
+ joinrec {
+ step'_sTs [Occ=LoopBreaker, Dmd=SC(S,!P(L,L,L))]
+ :: Int# -> (# Int#, Int#, Array# Double #)
+ [LclId[JoinId(1)(Nothing)], Arity=1, Str=<L>, Unf=OtherCon []]
+ step'_sTs (i1_X1 :: Int#)
+ = case >=# i1_X1 n_axM of {
+ __DEFAULT ->
+ case indexArray# @'Lifted @Double oldArr_axN (+# off_axL i1_X1) of
+ { (# ipv2_sSW #) ->
+ case ipv2_sSW of { D# x_aPv ->
+ case >## x_aPv 10.0## of {
+ __DEFAULT -> jump step'_sTs (+# i1_X1 1#);
+ 1# -> jump exit1_X4 i1_X1 x_aPv
+ }
+ }
+ };
+ 1# -> jump $j_sTM
+ }; } in
+ jump step'_sTs i_ay0; } in
+ jump loop_sTq 0# 0# ipv_sSS
+ })
+
+-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
+Unboxed.$trModule3 :: GHC.Types.TrName
+[GblId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
+ WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
+Unboxed.$trModule3 = GHC.Types.TrNameS Unboxed.$trModule4
+
+-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
+Unboxed.$trModule1 :: GHC.Types.TrName
+[GblId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
+ WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
+Unboxed.$trModule1 = GHC.Types.TrNameS Unboxed.$trModule2
+
+-- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0}
+Unboxed.$trModule :: GHC.Types.Module
+[GblId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
+ WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
+Unboxed.$trModule
+ = GHC.Types.Module Unboxed.$trModule3 Unboxed.$trModule1
+
+-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
+$krep_rV0 :: GHC.Types.KindRep
+[GblId, Unf=OtherCon []]
+$krep_rV0 = GHC.Types.KindRepVar 1#
+
+-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
+$krep1_rV1 :: GHC.Types.KindRep
+[GblId, Unf=OtherCon []]
+$krep1_rV1 = GHC.Types.KindRepVar 0#
+
+-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
+Unboxed.$tcStep2 :: Addr#
+[GblId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
+ WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 20 0}]
+Unboxed.$tcStep2 = "Step"#
+
+-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
+Unboxed.$tcStep1 :: GHC.Types.TrName
+[GblId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
+ WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
+Unboxed.$tcStep1 = GHC.Types.TrNameS Unboxed.$tcStep2
+
+-- RHS size: {terms: 7, types: 0, coercions: 0, joins: 0/0}
+Unboxed.$tcStep :: GHC.Types.TyCon
+[GblId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
+ WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
+Unboxed.$tcStep
+ = GHC.Types.TyCon
+ 9345441458829744813##64
+ 15928240119707513573##64
+ Unboxed.$trModule
+ Unboxed.$tcStep1
+ 0#
+ GHC.Types.krep$*->*->*
+
+-- RHS size: {terms: 3, types: 2, coercions: 0, joins: 0/0}
+$krep2_rV2 :: [GHC.Types.KindRep]
+[GblId, Unf=OtherCon []]
+$krep2_rV2
+ = GHC.Types.:
+ @GHC.Types.KindRep $krep_rV0 (GHC.Types.[] @GHC.Types.KindRep)
+
+-- RHS size: {terms: 3, types: 1, coercions: 0, joins: 0/0}
+$krep3_rV3 :: [GHC.Types.KindRep]
+[GblId, Unf=OtherCon []]
+$krep3_rV3 = GHC.Types.: @GHC.Types.KindRep $krep1_rV1 $krep2_rV2
+
+-- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0}
+Unboxed.$tc'Done1 [InlPrag=[~]] :: GHC.Types.KindRep
+[GblId, Unf=OtherCon []]
+Unboxed.$tc'Done1
+ = GHC.Types.KindRepTyConApp Unboxed.$tcStep $krep3_rV3
+
+-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
+Unboxed.$tc'Done3 :: Addr#
+[GblId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
+ WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 30 0}]
+Unboxed.$tc'Done3 = "'Done"#
+
+-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
+Unboxed.$tc'Done2 :: GHC.Types.TrName
+[GblId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
+ WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
+Unboxed.$tc'Done2 = GHC.Types.TrNameS Unboxed.$tc'Done3
+
+-- RHS size: {terms: 7, types: 0, coercions: 0, joins: 0/0}
+Unboxed.$tc'Done :: GHC.Types.TyCon
+[GblId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
+ WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
+Unboxed.$tc'Done
+ = GHC.Types.TyCon
+ 12965714903249458155##64
+ 720712123234526269##64
+ Unboxed.$trModule
+ Unboxed.$tc'Done2
+ 2#
+ Unboxed.$tc'Done1
+
+-- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0}
+$krep4_rV4 :: GHC.Types.KindRep
+[GblId, Unf=OtherCon []]
+$krep4_rV4 = GHC.Types.KindRepFun $krep1_rV1 Unboxed.$tc'Done1
+
+-- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0}
+Unboxed.$tc'Yield1 [InlPrag=[~]] :: GHC.Types.KindRep
+[GblId, Unf=OtherCon []]
+Unboxed.$tc'Yield1 = GHC.Types.KindRepFun $krep_rV0 $krep4_rV4
+
+-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
+Unboxed.$tc'Yield3 :: Addr#
+[GblId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
+ WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 30 0}]
+Unboxed.$tc'Yield3 = "'Yield"#
+
+-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
+Unboxed.$tc'Yield2 :: GHC.Types.TrName
+[GblId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
+ WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
+Unboxed.$tc'Yield2 = GHC.Types.TrNameS Unboxed.$tc'Yield3
+
+-- RHS size: {terms: 7, types: 0, coercions: 0, joins: 0/0}
+Unboxed.$tc'Yield :: GHC.Types.TyCon
+[GblId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
+ WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
+Unboxed.$tc'Yield
+ = GHC.Types.TyCon
+ 16456917800457442198##64
+ 7357499335137316903##64
+ Unboxed.$trModule
+ Unboxed.$tc'Yield2
+ 2#
+ Unboxed.$tc'Yield1
+
+
+
=====================================
testsuite/tests/simplCore/should_compile/all.T
=====================================
@@ -428,5 +428,7 @@ test('T21763', only_ways(['optasm']), compile, ['-O2 -ddump-rules'])
test('T21763a', only_ways(['optasm']), compile, ['-O2 -ddump-rules'])
test('T22028', normal, compile, ['-O -ddump-rule-firings'])
test('T22114', normal, compile, ['-O'])
-test('T21286', normal, multimod_compile, ['T21286', '-O -ddump-rule-firings'])
+test('T21286', normal, multimod_compile, ['T21286', '-O -ddump-rule-firings'])
+# step should be loopified and turned into a join point
+test('T22227', [grep_errmsg(r'jump \S*step') ], compile, ['-O -ddump-simpl'])
=====================================
testsuite/tests/stranal/sigs/T5075.hs
=====================================
@@ -17,10 +17,10 @@ g x y = go x
True -> Just x
False -> go (x*2)
--- Here, go is not a join point, but still should be WW'd for Just.
--- Unfortunately, CPR can't see that (+?) returns Just, so h won't get the CPR
--- property. It probably could by only considering the @Just@ case of the
--- inlined (+?).
+-- Here, go is not a join point (call-site loopification doesn't trigger because
+-- it is marked NOINLINE), but still should be WW'd for Just. Unfortunately,
+-- CPR can't see that (+?) returns Just, so h won't get the CPR property. It
+-- probably could by only considering the @Just@ case of the inlined (+?).
h :: Int -> Maybe Int
h x = go x +? go (x+1)
where
@@ -29,3 +29,4 @@ h x = go x +? go (x+1)
go z
| z > 10 = Just (x + z)
| otherwise = go (z*2)
+ {-# NOINLINE go #-}
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/63c2f0df143bbee2804327f055d8e3fba7509307
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/63c2f0df143bbee2804327f055d8e3fba7509307
You're receiving this email because of your account on gitlab.haskell.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20221001/1919e851/attachment-0001.html>
More information about the ghc-commits
mailing list