git.iko.soy/rowtype-yoga/purescript-backend-optimizer
on main help sign in
Fix analysis and heuristic for derefs. (#40)

Captured derefs shouldn't be indiscriminately inlined, but this was happening due to a missing analysis. This isn't unsound or anything, as it's what the main compiler does, but it can lead to space leaks when an object is captured by a closure, but only certain fields are accessed. For now, I've kept the inlining if the field is known to be a function, or rather always called with arguments, since it results in much better codegen for typeclass code.

commitfb5e6a85d70c3f6346e350e52db868492e8455ee authorNathan Faubion <natefaubion@users.noreply.github.com> dateWed 21 Dec 2022, 09:41 (4 years ago) parentc37b527
4 files changed+34−3
backend-es/test/snapshots-out/Snapshot.CaptureDerefRegression01.js+12 backend-es/test/snapshots/Snapshot.CaptureDerefRegression01.purs+17 src/PureScript/Backend/Optimizer/Analysis.purs+1−1 src/PureScript/Backend/Optimizer/Semantics.purs+4−2
backend-es/test/snapshots-out/Snapshot.CaptureDerefRegression01.jsnew file+12
@@ -0,0 +1,12 @@
1+const $Box = _1 => ({tag: "Box", _1});
2+const Box = value0 => $Box(value0);
3+const test3 = v => {
4+ const $0 = v._1;
5+ return $Box(b => $0 + b | 0);
6+};
7+const test2 = v => {
8+ const $0 = v._1;
9+ return b => $0 + b | 0;
10+};
11+const test1 = v => b => v._1 + b | 0;
12+export {$Box, Box, test1, test2, test3};
backend-es/test/snapshots/Snapshot.CaptureDerefRegression01.pursnew file+17
@@ -0,0 +1,17 @@
1+module Snapshot.CaptureDerefRegression01 where
2+
3+import Prelude
4+
5+import Data.Identity (Identity(..))
6+import Data.Tuple (Tuple(..))
7+
8+data Box a = Box a
9+
10+test1 :: Tuple Int Int -> Int -> Int
11+test1 (Tuple a _) b = a + b
12+
13+test2 :: Tuple Int Int -> Identity (Int -> Int)
14+test2 (Tuple a _) = Identity \b -> a + b
15+
16+test3 :: Tuple Int Int -> Box (Int -> Int)
17+test3 (Tuple a _) = Box \b -> a + b
src/PureScript/Backend/Optimizer/Analysis.purs+1−1
@@ -341,7 +341,7 @@ analyze externAnalysis expr = case expr of
341341 Just (Accessor _ _) ->
342342 analysis
343343 Just (Local _ lvl) ->
344− accessed lvl analysis
344+ accessed lvl $ complex Deref analysis
345345 Just (Var qi) -> do
346346 let BackendAnalysis { args } = externAnalysis (Tuple qi (Just acc))
347347 withArgs args $ complex Trivial analysis
src/PureScript/Backend/Optimizer/Semantics.purs+4−2
@@ -1475,9 +1475,11 @@ shouldInlineLet level a b = do
14751475 case Map.lookup level s2.usages of
14761476 Nothing ->
14771477 true
1478− Just (Usage { captured, total }) ->
1478+ Just (Usage { captured, total, call }) ->
14791479 (s1.complexity == Trivial)
1480− || (captured == CaptureNone && (total == 1 || (s1.complexity <= Deref && s1.size < 5)))
1480+ || (captured == CaptureNone && total == 1)
1481+ || (captured <= CaptureBranch && s1.complexity <= Deref && s1.size < 5)
1482+ || (s1.complexity == Deref && call == total)
14811483 || (s1.complexity == KnownSize && total == 1)
14821484 || (isAbs a && (total == 1 || Map.isEmpty s1.usages || s1.size < 16))
14831485 || (isKnownEffect a && total == 1)