postInlineUnconditionally for join points causes multiple Simplifier iterations, and exponential code blowup
In the existing test perf/compiler/T13253-spj
(a nice, small, easily-scalable test) we tend to get multiple simplifier iterations, in the Simplifier FinalPhase.
Reason:
-
postInlineUnconditionally
is currently switched off altogether for join point, until FinalPhase. - Then it see something like
j1 x = .... j2 x = ...j1 j3 x = ...j1 in case p of .. -> j3 x .. -> j3 x .. -> j2 x
- The OccInfo on
j3
isOneOcc { n_br=2 }
; sopostInlineUconditinally
may fire. - But the OccInfo on
j1
isManyOcc
because it is used in the RHS of bothj2
andj3
. This is a shortcoming of the occurrence analyser (#22404 (closed)). - So
j1
does not inline; butj3
does. - But now, in the next iteration of the Simplifer, the OccInfo on
j1
isOneOcc
, so it inlines.
In T13253-spj, this cascades and each iteration of the Simplifier inlines just one pair of join points. Worse, it's an exponential thing: each double the size of the case tree.
The only thing that currently stops it is that postInlineUnconditionally
has an arbitrary n_br < 100
limit, so it stops when one of the join point has more than a hundred calls.
For the record, here is what it looks like, just before that FinalPhase simplification.
foo
= \ (y_aI4 :: Int) (x_aI5 :: Bool) ->
join {
$j_sPz :: Bool
[LclId[JoinId(0)(Nothing)]]
$j_sPz
= case y_aI4 of { GHC.Types.I# x_aP5 ->
GHC.Prim.tagToEnum# @Bool (GHC.Prim.># (GHC.Prim.+# x_aP5 1#) 0#)
} } in
join {
$j_sPy :: Bool
[LclId[JoinId(0)(Nothing)]]
$j_sPy
= case y_aI4 of { GHC.Types.I# x_aP5 ->
GHC.Prim.tagToEnum# @Bool (GHC.Prim.<# (GHC.Prim.+# x_aP5 1#) 0#)
} } in
join {
$j_sPB :: Bool
[LclId[JoinId(0)(Nothing)]]
$j_sPB
= case y_aI4 of { GHC.Types.I# x_aP5 ->
case GHC.Prim.># (GHC.Prim.+# x_aP5 2#) 0# of {
__DEFAULT -> jump $j_sPy;
1# -> jump $j_sPz
}
} } in
join {
$j_sPA :: Bool
[LclId[JoinId(0)(Nothing)]]
$j_sPA
= case y_aI4 of { GHC.Types.I# x_aP5 ->
case GHC.Prim.<# (GHC.Prim.+# x_aP5 2#) 0# of {
__DEFAULT -> jump $j_sPy;
1# -> jump $j_sPz
}
} } in
join {
$j_sPD :: Bool
[LclId[JoinId(0)(Nothing)]]
$j_sPD
= case y_aI4 of { GHC.Types.I# x_aP5 ->
case GHC.Prim.># (GHC.Prim.+# x_aP5 3#) 0# of {
__DEFAULT -> jump $j_sPA;
1# -> jump $j_sPB
}
} } in
join {
$j_sPC :: Bool
[LclId[JoinId(0)(Nothing)]]
$j_sPC
= case y_aI4 of { GHC.Types.I# x_aP5 ->
case GHC.Prim.<# (GHC.Prim.+# x_aP5 3#) 0# of {
__DEFAULT -> jump $j_sPA;
1# -> jump $j_sPB
}
} } in
join {
$j_sPF :: Bool
[LclId[JoinId(0)(Nothing)]]
$j_sPF
= case y_aI4 of { GHC.Types.I# x_aP5 ->
case GHC.Prim.># (GHC.Prim.+# x_aP5 4#) 0# of {
__DEFAULT -> jump $j_sPC;
1# -> jump $j_sPD
}
} } in
join {
$j_sPE :: Bool
[LclId[JoinId(0)(Nothing)]]
$j_sPE
= case y_aI4 of { GHC.Types.I# x_aP5 ->
case GHC.Prim.<# (GHC.Prim.+# x_aP5 4#) 0# of {
__DEFAULT -> jump $j_sPC;
1# -> jump $j_sPD
}
} } in
join {
$j_sPH :: Bool
[LclId[JoinId(0)(Nothing)]]
$j_sPH
= case y_aI4 of { GHC.Types.I# x_aP5 ->
case GHC.Prim.># (GHC.Prim.+# x_aP5 5#) 0# of {
__DEFAULT -> jump $j_sPE;
1# -> jump $j_sPF
}
} } in
join {
$j_sPG :: Bool
[LclId[JoinId(0)(Nothing)]]
$j_sPG
= case y_aI4 of { GHC.Types.I# x_aP5 ->
case GHC.Prim.<# (GHC.Prim.+# x_aP5 5#) 0# of {
__DEFAULT -> jump $j_sPE;
1# -> jump $j_sPF
}
} } in
join {
$j_sPJ :: Bool
[LclId[JoinId(0)(Nothing)]]
$j_sPJ
= case y_aI4 of { GHC.Types.I# x_aP5 ->
case GHC.Prim.># (GHC.Prim.+# x_aP5 6#) 0# of {
__DEFAULT -> jump $j_sPG;
1# -> jump $j_sPH
}
} } in
join {
$j_sPI :: Bool
[LclId[JoinId(0)(Nothing)]]
$j_sPI
= case y_aI4 of { GHC.Types.I# x_aP5 ->
case GHC.Prim.<# (GHC.Prim.+# x_aP5 6#) 0# of {
__DEFAULT -> jump $j_sPG;
1# -> jump $j_sPH
}
} } in
join {
$j_sPL :: Bool
[LclId[JoinId(0)(Nothing)]]
$j_sPL
= case y_aI4 of { GHC.Types.I# x_aP5 ->
case GHC.Prim.># (GHC.Prim.+# x_aP5 7#) 0# of {
__DEFAULT -> jump $j_sPI;
1# -> jump $j_sPJ
}
} } in
join {
$j_sPK :: Bool
[LclId[JoinId(0)(Nothing)]]
$j_sPK
= case y_aI4 of { GHC.Types.I# x_aP5 ->
case GHC.Prim.<# (GHC.Prim.+# x_aP5 7#) 0# of {
__DEFAULT -> jump $j_sPI;
1# -> jump $j_sPJ
}
} } in
join {
$j_sPN :: Bool
[LclId[JoinId(0)(Nothing)]]
$j_sPN
= case y_aI4 of { GHC.Types.I# x_aP5 ->
case GHC.Prim.># (GHC.Prim.+# x_aP5 8#) 0# of {
__DEFAULT -> jump $j_sPK;
1# -> jump $j_sPL
}
} } in
join {
$j_sPM :: Bool
[LclId[JoinId(0)(Nothing)]]
$j_sPM
= case y_aI4 of { GHC.Types.I# x_aP5 ->
case GHC.Prim.<# (GHC.Prim.+# x_aP5 8#) 0# of {
__DEFAULT -> jump $j_sPK;
1# -> jump $j_sPL
}
} } in
join {
$j_sPP :: Bool
[LclId[JoinId(0)(Nothing)]]
$j_sPP
= case y_aI4 of { GHC.Types.I# x_aP5 ->
case GHC.Prim.># (GHC.Prim.+# x_aP5 9#) 0# of {
__DEFAULT -> jump $j_sPM;
1# -> jump $j_sPN
}
} } in
join {
$j_sPO :: Bool
[LclId[JoinId(0)(Nothing)]]
$j_sPO
= case y_aI4 of { GHC.Types.I# x_aP5 ->
case GHC.Prim.<# (GHC.Prim.+# x_aP5 9#) 0# of {
__DEFAULT -> jump $j_sPM;
1# -> jump $j_sPN
}
} } in
join {
$j_sPR :: Bool
[LclId[JoinId(0)(Nothing)]]
$j_sPR
= case y_aI4 of { GHC.Types.I# x_aP5 ->
case GHC.Prim.># (GHC.Prim.+# x_aP5 10#) 0# of {
__DEFAULT -> jump $j_sPO;
1# -> jump $j_sPP
}
} } in
join {
$j_sPQ :: Bool
[LclId[JoinId(0)(Nothing)]]
$j_sPQ
= case y_aI4 of { GHC.Types.I# x_aP5 ->
case GHC.Prim.<# (GHC.Prim.+# x_aP5 10#) 0# of {
__DEFAULT -> jump $j_sPO;
1# -> jump $j_sPP
}
} } in
join {
$j_sPT :: Bool
[LclId[JoinId(0)(Nothing)],
Unf=Unf{Src=<vanilla>, TopLvl=False,
Value=False, ConLike=False, WorkFree=False, Expandable=False,
Guidance=IF_ARGS [] 36 0}]
$j_sPT
= case y_aI4 of { GHC.Types.I# x_aP5 ->
case GHC.Prim.># (GHC.Prim.+# x_aP5 11#) 0# of {
__DEFAULT -> jump $j_sPQ;
1# -> jump $j_sPR
}
} } in
join {
$j_sPS :: Bool
[LclId[JoinId(0)(Nothing)],
Unf=Unf{Src=<vanilla>, TopLvl=False,
Value=False, ConLike=False, WorkFree=False, Expandable=False,
Guidance=IF_ARGS [] 36 0}]
$j_sPS
= case y_aI4 of { GHC.Types.I# x_aP5 ->
case GHC.Prim.<# (GHC.Prim.+# x_aP5 11#) 0# of {
__DEFAULT -> jump $j_sPQ;
1# -> jump $j_sPR
}
} } in
case x_aI5 of {
False ->
case y_aI4 of { GHC.Types.I# x_aPX ->
case GHC.Prim.<# x_aPX 0# of {
__DEFAULT -> jump $j_sPS;
1# -> jump $j_sPT
}
};
True ->
case y_aI4 of { GHC.Types.I# x_aQ5 ->
case GHC.Prim.># x_aQ5 0# of {
__DEFAULT -> jump $j_sPS;
1# -> jump $j_sPT
}
}
}