@@ -80,9 +80,6 @@ module Unison.Runtime.ANF
80
80
valueTermLinks ,
81
81
valueLinks ,
82
82
groupTermLinks ,
83
- buildInlineMap ,
84
- inline ,
85
- optimizeHandler ,
86
83
replaceConstructors ,
87
84
replaceFunctions ,
88
85
foldGroup ,
@@ -102,13 +99,11 @@ import Control.Exception (throw)
102
99
import Control.Lens (snoc , unsnoc )
103
100
import Control.Monad.Reader (ReaderT (.. ), ask , local )
104
101
import Control.Monad.State (MonadState (.. ), State , gets , modify , runState )
105
- import Control.Monad.Writer (WriterT (.. ), tell )
106
102
import Data.Bifoldable (Bifoldable (.. ))
107
103
import Data.Bitraversable (Bitraversable (.. ))
108
104
import Data.Functor.Compose (Compose (.. ))
109
105
import Data.List hiding (and , or )
110
106
import Data.Map qualified as Map
111
- import Data.Monoid (Any (.. ))
112
107
import Data.Set qualified as Set
113
108
import Data.Text qualified as Data.Text
114
109
import GHC.Stack (CallStack , callStack )
@@ -139,7 +134,6 @@ import Unison.Util.Text qualified as Util.Text
139
134
import Unison.Var (Var , typed )
140
135
import Unison.Var qualified as Var
141
136
import Prelude hiding (abs , and , or , seq )
142
- import Prelude qualified
143
137
144
138
-- For internal errors
145
139
data CompileExn = CE CallStack (Pretty. Pretty Pretty. ColorText )
@@ -664,46 +658,6 @@ saturate dat = ABT.visitPure $ \case
664
658
fvs = foldMap freeVars args
665
659
args' = saturate dat <$> args
666
660
667
- -- Performs inlining on a supergroup using the inlining information
668
- -- in the map. The map can be created from typical SuperGroup data
669
- -- using the `buildInlineMap` function.
670
- inline ::
671
- (Var v ) =>
672
- Map Reference (Int , ANormal v ) ->
673
- SuperGroup v ->
674
- SuperGroup v
675
- inline inls (Rec bs entry) = Rec (fmap go0 <$> bs) (go0 entry)
676
- where
677
- go0 (Lambda ccs body) = Lambda ccs $ go (30 :: Int ) body
678
- -- Note: number argument bails out in recursive inlining cases
679
- go n | n <= 0 = id
680
- go n = ABTN. visitPure \ case
681
- TApp (FComb r) args
682
- | Just (arity, expr) <- Map. lookup r inls ->
683
- go (n - 1 ) <$> tweak expr args arity
684
- TName nv (Left r) args body
685
- | Just (arity, expr) <- Map. lookup r inls ->
686
- tweak expr args arity >>= \ case
687
- TCom r args ->
688
- Just . go (n- 1 ) $ TName nv (Left r) args body
689
- TApv v args ->
690
- Just . go (n- 1 ) $ TName nv (Right v) args body
691
- _ -> Nothing
692
- _ -> Nothing
693
-
694
- tweak (ABTN. TAbss vs body) args arity
695
- -- exactly saturated
696
- | length args == arity,
697
- rn <- Map. fromList (zip vs args) =
698
- Just $ ABTN. renames rn body
699
- -- oversaturated, only makes sense if body is a call
700
- | length args > arity,
701
- (pre, post) <- splitAt arity args,
702
- rn <- Map. fromList (zip vs pre),
703
- TApp f pre <- ABTN. renames rn body =
704
- Just $ TApp f (pre ++ post)
705
- | otherwise = Nothing
706
-
707
661
replaceConstructors ::
708
662
(Var v ) =>
709
663
Map Reference (Map CTag ForeignFunc ) ->
@@ -1593,269 +1547,6 @@ arity (Lambda ccs _) = length ccs
1593
1547
arities :: SuperGroup v -> [Int ]
1594
1548
arities (Rec bs e) = arity e : fmap (arity . snd ) bs
1595
1549
1596
- -- Checks the body of a SuperGroup makes it eligible for inlining.
1597
- -- See below for the discussion.
1598
- isInlinable :: (Var v ) => Reference -> ANormal v -> Bool
1599
- isInlinable r (TApp (FComb s) _) = r /= s
1600
- isInlinable _ TApp {} = True
1601
- isInlinable _ TBLit {} = True
1602
- isInlinable _ TVar {} = True
1603
- isInlinable _ _ = False
1604
-
1605
- -- Checks a SuperGroup makes it eligible to be inlined.
1606
- -- Unfortunately we need to be quite conservative about this.
1607
- --
1608
- -- The heuristic implemented below is as follows:
1609
- --
1610
- -- 1. There are no local bindings, so only the 'entry point'
1611
- -- matters.
1612
- -- 2. The entry point body is just a single expression, that is,
1613
- -- an application, variable or literal.
1614
- --
1615
- -- The first condition ensures that there isn't any need to jump
1616
- -- into a non-entrypoint from outside a group. These should be rare
1617
- -- anyway, because the local bindings are no longer used for
1618
- -- (unison-level) local function definitions (those are lifted
1619
- -- out). The second condition ensures that inlining the body should
1620
- -- have no effect on the runtime stack of of the function we're
1621
- -- inlining into, because the combinator is just a wrapper around
1622
- -- the simple expression.
1623
- --
1624
- -- Fortunately, it should be possible to make _most_ builtins have
1625
- -- this form, so that their instructions can be inlined directly
1626
- -- into the call sites when saturated.
1627
- --
1628
- -- The result of this function is the information necessary to
1629
- -- inline the combinator—an arity and the body expression with
1630
- -- bound variables. This should allow checking if the call is
1631
- -- saturated and make it possible to locally substitute for an
1632
- -- inlined expression.
1633
- --
1634
- -- The `Reference` argument allows us to check if the body is a
1635
- -- direct recursive call to the same function, which would result
1636
- -- in infinite inlining. This isn't the only such scenario, but
1637
- -- it's one we can opportunistically rule out.
1638
- inlineInfo :: (Var v ) => Reference -> SuperGroup v -> Maybe (Int , ANormal v )
1639
- inlineInfo r (Rec [] (Lambda ccs body@ (ABTN. TAbss _ e)))
1640
- | isInlinable r e = Just (length ccs, body)
1641
- inlineInfo _ _ = Nothing
1642
-
1643
- -- Builds inlining information from a collection of SuperGroups.
1644
- -- They are all tested for inlinability, and the result map
1645
- -- contains only the information for groups that are able to be
1646
- -- inlined.
1647
- buildInlineMap ::
1648
- (Var v ) =>
1649
- Map Reference (SuperGroup v ) ->
1650
- Map Reference (Int , ANormal v )
1651
- buildInlineMap =
1652
- runIdentity
1653
- . Map. traverseMaybeWithKey (\ r g -> Identity $ inlineInfo r g)
1654
-
1655
- -- If the provided SuperGroup is recognized as a handler, applies
1656
- -- optimizations to improve it, like adding better code for affine
1657
- -- handlers.
1658
- optimizeHandler :: Var v => Reference -> SuperGroup v -> SuperGroup v
1659
- optimizeHandler self group =
1660
- fromMaybe group $ augmentHandler self group
1661
-
1662
- -- moves the last value of a list to the start, for easier matching
1663
- shiftArgs :: [v ] -> [v ]
1664
- shiftArgs vs = case reverse vs of
1665
- v : vs -> v : reverse vs
1666
- [] -> []
1667
-
1668
- -- Checks if the group represents a handler, and if so, tries to add
1669
- -- optimized affine code.
1670
- augmentHandler ::
1671
- (Var v ) => Reference -> SuperGroup v -> Maybe (SuperGroup v )
1672
- augmentHandler self group
1673
- | Rec [(mv0, matcher)] entry <- group,
1674
- Lambda ccs (ABTN. TAbss args body) <- entry,
1675
- thunk : vs <- shiftArgs args,
1676
- Just body <- augmentHandlerEntry vs thunk mv0 ah body,
1677
- Just amatcher <- translateHandlerMatch self ah matcher =
1678
- Just .
1679
- Rec [(mv0, matcher), (ah, amatcher)] .
1680
- Lambda ccs $
1681
- ABTN. TAbss args body
1682
-
1683
- | otherwise = Nothing
1684
- where
1685
- ah = freshAff 0
1686
-
1687
- -- Recognizes the matching portion of a handler, and produces an
1688
- -- optimized affine version if possible.
1689
- translateHandlerMatch
1690
- :: Var v => Reference -> v -> SuperNormal v -> Maybe (SuperNormal v )
1691
- translateHandlerMatch self ah (Lambda ccs (ABTN. TAbss args body))
1692
- | v : vs <- shiftArgs args,
1693
- TMatch u branches <- body, u == v,
1694
- MatchRequest cs df <- branches,
1695
- args <- vs ++ [ar, v],
1696
- ccs <- ccs ++ [BX ] =
1697
- Lambda ccs . ABTN. TAbss args . TMatch u . flip MatchRequest df <$>
1698
- traverse3 (affineHandlerCase self vs ah) cs
1699
-
1700
- | otherwise = Nothing
1701
-
1702
- where
1703
- ar = freshAff 2
1704
- traverse3 = traverse . traverse . traverse
1705
-
1706
- -- Recognizes the entry combinator of a compiled handler. If it is
1707
- -- one, then the result is a modified version with an affine handler
1708
- -- filled in.
1709
- augmentHandlerEntry ::
1710
- Var v => [v ] -> v -> v -> v -> ANormal v -> Maybe (ANormal v )
1711
- augmentHandlerEntry vs thunk0 mv0 ah body
1712
- | TName hv (Right mv1) us body <- body,
1713
- THnd rs nh Nothing (TFrc thunk1) <- body,
1714
- mv0 == mv1, nh == hv, thunk0 == thunk1,
1715
- Prelude. and (zipWith (==) us vs) =
1716
- Just .
1717
- TName hv (Right mv1) us .
1718
- TName ahp (Right ah) us $
1719
- THnd rs nh (Just ahp) (TFrc thunk1)
1720
-
1721
- | otherwise = Nothing
1722
- where
1723
- ahp = freshAff 1
1724
-
1725
- -- Recognizes an affine handler case, yielding a translated efficient
1726
- -- version if it is one.
1727
- affineHandlerCase ::
1728
- Var v => Reference -> [v ] -> v -> ANormal v -> Maybe (ANormal v )
1729
- affineHandlerCase self vs rec br
1730
- | ABTN. TAbss us body <- br,
1731
- TShift _ kf0 body <- body,
1732
- TName kf (Left (Builtin " jumpCont" )) [kf1] body <- body,
1733
- kf0 == kf1 =
1734
- ABTN. TAbss us <$>
1735
- affinePreBranch self Set. empty vs rec ar kf body
1736
-
1737
- | otherwise = Nothing
1738
- where
1739
- ar = freshAff 2
1740
-
1741
- -- Allows for having multiple branches that differ in the exact type
1742
- -- of affine handler recognized.
1743
- --
1744
- -- If the entire term doesn't use the continuation, then an irrelevant
1745
- -- handler is generated.
1746
- --
1747
- -- If the immediate term is a match, then we delay the choice of which
1748
- -- type of handler to generate into each branch.
1749
- --
1750
- -- If neither of the above cases hold, then we look for a linear case.
1751
- affinePreBranch ::
1752
- Var v =>
1753
- Reference ->
1754
- Set v ->
1755
- [v ] ->
1756
- v ->
1757
- v ->
1758
- v ->
1759
- ANormal v ->
1760
- Maybe (ANormal v )
1761
- affinePreBranch self bound vs rec ar kf bd
1762
- | Just it <- irrelevantTail ar kf bd = Just it
1763
-
1764
- | TMatch v bs <- bd =
1765
- TMatch v <$>
1766
- for bs \ case
1767
- ABTN. TAbss us bd ->
1768
- ABTN. TAbss us <$>
1769
- affinePreBranch self bound' vs rec ar kf bd
1770
- where
1771
- bound' = Set. union (Set. fromList us) bound
1772
-
1773
- | otherwise =
1774
- localize <$>
1775
- runWriterT (translateLinear self bound vs rec ar kf bd)
1776
- where
1777
- localize (tm, Any True ) = TLocal ar tm
1778
- localize (tm, Any False ) = tm
1779
-
1780
- translateLinear ::
1781
- Var v =>
1782
- Reference ->
1783
- Set v ->
1784
- [v ] ->
1785
- v ->
1786
- v ->
1787
- v ->
1788
- ANormal v ->
1789
- WriterT Any Maybe (ANormal v )
1790
- translateLinear self bound0 vs rec ar kf = go bound0
1791
- where
1792
- go bound body
1793
- | Just lt <- linearTail self vs bound rec ar kf body =
1794
- lt <$ tell (Any True )
1795
-
1796
- | Just it <- irrelevantTail ar kf body = pure it
1797
-
1798
- | TLet d v cc e body <- body,
1799
- kf `Set.notMember` ABTN. freeVars e =
1800
- TLet d v cc e <$> go (Set. insert v bound) body
1801
-
1802
- | TName v f us body <- body,
1803
- all (kf /= ) us =
1804
- TName v f us <$> go (Set. insert v bound) body
1805
-
1806
- | TMatch v bs <- body =
1807
- TMatch v <$>
1808
- for bs \ case
1809
- ABTN. TAbss us bd ->
1810
- ABTN. TAbss us <$>
1811
- go (Set. fromList us `Set.union` bound) bd
1812
-
1813
- | otherwise = mzero
1814
-
1815
- -- Recognizes the tail of a linear handler case, where the
1816
- -- continuation is called once in tail position. Returns a transformed
1817
- -- version if a match is found.
1818
- --
1819
- -- Arguments:
1820
- -- self: Reference to handler combinator
1821
- -- bound: arguments bound since header
1822
- -- vs: arguments to handler combinator
1823
- -- rec: local variable for affine handler
1824
- -- ar: argument variable for affine handler info
1825
- -- kf0: continuation variable
1826
- -- tm: term to transform
1827
- --
1828
- -- Note: this relies on inlining into the thunked continuation call to
1829
- -- avoid see exactly what the `k result` call is, rather than it
1830
- -- having multiple forms depending on the variable order.
1831
- linearTail ::
1832
- Var v => Reference -> [v ] -> Set v -> v -> v -> v -> ANormal v -> Maybe (ANormal v )
1833
- linearTail self vs bound rec ar kf0 tm
1834
- | TLet _ hr0 _ (TCom r us) tm <- tm, -- recursive handler call
1835
- TName thunk0 (Right kf1) [result] tm <- tm, -- lazy cont resume
1836
- TApv hr1 [thunk1] <- tm, -- apply handler to thunk
1837
- r == self, kf0 == kf1, thunk0 == thunk1, hr0 == hr1 =
1838
- Just . update hr0 us $ TVar result
1839
-
1840
- | otherwise = Nothing
1841
-
1842
- where
1843
- update huv us
1844
- -- recursive call with identical, non-shadowed variables;
1845
- -- no need to update
1846
- | Prelude. and (zipWith (==) us vs),
1847
- all (`Set.notMember` bound) us = id
1848
- -- repurpose hr0 variable for update call
1849
- | otherwise =
1850
- TName huv (Right rec ) (us ++ [ar]) .
1851
- TLets Direct [] [] (TUpdate ar huv)
1852
-
1853
- irrelevantTail :: Var v => v -> v -> ANormal v -> Maybe (ANormal v )
1854
- irrelevantTail ar kf tm
1855
- | kf `Set.notMember` ABTN. freeVars tm =
1856
- Just $ TLets Direct [] [] (TDiscard ar) tm
1857
- | otherwise = Nothing
1858
-
1859
1550
-- Checks if two SuperGroups are equivalent up to renaming. The rest
1860
1551
-- of the structure must match on the nose. If the two groups are not
1861
1552
-- equivalent, an example of conflicting structure is returned.
@@ -1967,9 +1658,6 @@ bindLocal vs = local (Set.\\ Set.fromList vs)
1967
1658
freshANF :: (Var v ) => Word64 -> v
1968
1659
freshANF fr = Var. freshenId fr $ typed Var. ANFBlank
1969
1660
1970
- freshAff :: (Var v ) => Word64 -> v
1971
- freshAff fr = Var. freshenId fr $ typed Var. AffBlank
1972
-
1973
1661
fresh :: (Var v ) => ANFM v v
1974
1662
fresh = state $ \ (fr, bnd, cs) -> (freshANF fr, (fr + 1 , bnd, cs))
1975
1663
0 commit comments