Follow-up from #180. Once a dictionary method is inlined, an inlined comparison
(compare, >=, <) leaves a residual Eq lit (if ...) that no rule folds, so
a guard that should reduce to a single primitive stays a verbose Ordering
if-tree.
Example
Golden.TailRecM2Shadow has the guard go acc i | i >= n = .... i >= n goes
through the Ord Int dictionary as compare i n followed by a tag test.
After #180 inlines compare and pushes the tag read into the branches (the
reflectCtor-through-if fold added in #180), the guard is left as:
Eq "Ordering.LT" (if i < n then "Ordering.LT" else if i == n then "Ordering.EQ" else "Ordering.GT")
constantFolding handles Eq lit lit, but here the second operand is an if,
not a literal, so nothing fires. The three-way Ordering conditional survives
into the generated Lua. This is the residual growth in TailRecM2Shadow
(+112 lines) noted on #180.
Proposed fix
A commuting conversion that distributes Eq over a conditional, guarded (as the
reflectCtor-through-if fold is) to fire only when the branches are literals
so the pushed Eq lit lit folds and no conditional is grown over
non-literal branches:
Eq lit (IfThenElse c t e) ==> IfThenElse c (Eq lit t) (Eq lit e) -- when t, e fold
The existing rules then finish the job:
Eq "LT" (if i<n then "LT" else if i==n then "EQ" else "GT")
-> if i<n then Eq "LT" "LT" else if i==n then Eq "LT" "EQ" else Eq "LT" "GT"
-> if i<n then True else if i==n then False else False -- constantFolding
-> if i<n then True else False -- removeIfWithEqualBranches
-> i < n -- reduceBooleanIf
The whole Ordering machinery collapses to one primitive i < n.
Note
Eq is one of the most common operations, so even guarded this fires on many
sites and will move a fair number of goldens. Worth measuring the corpus churn
before committing, which is why it is split out of #180 rather than riding along.
Follow-up from #180. Once a dictionary method is inlined, an inlined comparison
(
compare,>=,<) leaves a residualEq lit (if ...)that no rule folds, soa guard that should reduce to a single primitive stays a verbose
Orderingif-tree.
Example
Golden.TailRecM2Shadowhas the guardgo acc i | i >= n = ....i >= ngoesthrough the
Ord Intdictionary ascompare i nfollowed by a tag test.After #180 inlines
compareand pushes the tag read into the branches (thereflectCtor-through-iffold added in #180), the guard is left as:constantFoldinghandlesEq lit lit, but here the second operand is anif,not a literal, so nothing fires. The three-way
Orderingconditional survivesinto the generated Lua. This is the residual growth in
TailRecM2Shadow(+112 lines) noted on #180.
Proposed fix
A commuting conversion that distributes
Eqover a conditional, guarded (as thereflectCtor-through-iffold is) to fire only when the branches are literalsso the pushed
Eq lit litfolds and no conditional is grown overnon-literal branches:
The existing rules then finish the job:
The whole
Orderingmachinery collapses to one primitivei < n.Note
Eqis one of the most common operations, so even guarded this fires on manysites and will move a fair number of goldens. Worth measuring the corpus churn
before committing, which is why it is split out of #180 rather than riding along.