0 | module Compiler.Opts.InlineHeuristics
 1 |
 2 | import Core.CompileExpr
 3 | import Core.Context.Log
 4 | import Data.Vect
 5 | import Libraries.Data.WithDefault
 6 |
 7 | parameters (fn : Name)
 8 |     isVar : CExp vars -> Bool
 9 |     isVar (CLocal {}) = True
10 |     isVar (CRef {}) = True
11 |     isVar (CForce _ _ x) = isVar x
12 |     isVar (CDelay _ _ x) = isVar x
13 |     isVar _ = False
14 |
15 |     simple : CExp vars -> Bool
16 |     simple (CLocal {}) = True
17 |     simple (CRef {}) = True
18 |     simple (CLam {}) = False
19 |     simple (CLet {}) = False
20 |     simple (CApp _ (CRef _ fn') xs) = not (fn == fn') && all isVar xs
21 |     simple (CApp _ fn xs) = isVar fn && all isVar xs
22 |     simple (CCon _ _ _ _ xs) = all isVar xs
23 |     simple (COp _ _ xs) = all isVar xs
24 |     simple (CExtPrim _ _ xs) = all isVar xs
25 |     simple (CForce _ _ y) = simple y
26 |     simple (CDelay _ _ y) = simple y
27 |     simple (CConCase {}) = False
28 |     simple (CConstCase {}) = False
29 |     simple (CPrimVal {}) = True
30 |     simple (CErased {}) = True
31 |     simple (CCrash {}) = False
32 |
33 |     inlineCDef : CDef -> Bool
34 |     inlineCDef (MkFun args exp) =
35 |         simple exp
36 |     inlineCDef _ = False
37 |
38 | export
39 | inlineHeuristics : Ref Ctxt Defs => Name -> Core ()
40 | inlineHeuristics fn = do
41 |     defs <- get Ctxt
42 |     Just (fnIdx, gdef) <- lookupCtxtExactI fn defs.gamma
43 |         | Nothing => pure ()
44 |     let Just cdef = gdef.compexpr
45 |         | Nothing => pure ()
46 |     let True = inlineCDef fn cdef
47 |         | False => pure ()
48 |     -- We can't determine based on heuristics that something should be inlined unless
49 |     -- it is publicly exported because we may be crossing module boundaries and changes
50 |     -- to the given def will not modify the source module's interface hash so you can get
51 |     -- stuck with an old def inlined into the destination module. This is only a problem
52 |     -- when determining to inline based on heuristics, though -- if the definition was
53 |     -- explicitly marked for inlining by the programmer, it will be inlined without any
54 |     -- intervention by this function.
55 |     -- We could lift this public restriction if we checked that the source def was _either
56 |     -- public OR the destination was the same module as the source_.
57 |     let Public = collapseDefault $ gdef.visibility
58 |         | _ => pure ()
59 |     unless (NoInline `elem` gdef.flags) $ do
60 |       log "compiler.inline.heuristic" 25 $ "inlining heuristic decided to inline: " ++ show fn
61 |       setFlag EmptyFC (Resolved fnIdx) Inline
62 |