/- Copyright (c) 2019 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura -/ prelude import init.control.conditional import init.lean.compiler.initattr import init.lean.compiler.ir.compilerm /- Helper functions for backend code generators -/ namespace Lean namespace IR /- Return true iff `b` is of the form `let x := g ys; ret x` -/ def isTailCallTo (g : Name) (b : FnBody) : Bool := match b with | FnBody.vdecl x _ (Expr.fap f _) (FnBody.ret (Arg.var y)) => x == y && f == g | _ => false namespace UsesLeanNamespace abbrev M := ReaderT Environment (State NameSet) def leanNameSpacePrefix := `Lean partial def visitFnBody : FnBody → M Bool | (FnBody.vdecl _ _ v b) := let checkFn (f : FunId) : M Bool := if leanNameSpacePrefix.isPrefixOf f then pure true else do { s ← get; if s.contains f then visitFnBody b else do modify (fun s => s.insert f); env ← read; match findEnvDecl env f with | some (Decl.fdecl _ _ _ fbody) => visitFnBody fbody <||> visitFnBody b | other => visitFnBody b }; match v with | Expr.fap f _ => checkFn f | Expr.pap f _ => checkFn f | other => visitFnBody b | (FnBody.jdecl _ _ v b) := visitFnBody v <||> visitFnBody b | (FnBody.case _ _ alts) := alts.anyM $ fun alt => visitFnBody alt.body | e := if e.isTerminal then pure false else visitFnBody e.body end UsesLeanNamespace def usesLeanNamespace (env : Environment) : Decl → Bool | (Decl.fdecl _ _ _ b) := (UsesLeanNamespace.visitFnBody b env).run' {} | _ := false namespace CollectUsedDecls abbrev M := ReaderT Environment (State NameSet) @[inline] def collect (f : FunId) : M Unit := modify (fun s => s.insert f) partial def collectFnBody : FnBody → M Unit | (FnBody.vdecl _ _ v b) := match v with | Expr.fap f _ => collect f *> collectFnBody b | Expr.pap f _ => collect f *> collectFnBody b | other => collectFnBody b | (FnBody.jdecl _ _ v b) := collectFnBody v *> collectFnBody b | (FnBody.case _ _ alts) := alts.mfor $ fun alt => collectFnBody alt.body | e := unless e.isTerminal $ collectFnBody e.body def collectInitDecl (fn : Name) : M Unit := do env ← read; match getInitFnNameFor env fn with | some initFn => collect initFn | _ => pure () def collectDecl : Decl → M NameSet | (Decl.fdecl fn _ _ b) := collectInitDecl fn *> CollectUsedDecls.collectFnBody b *> get | (Decl.extern fn _ _ _) := collectInitDecl fn *> get end CollectUsedDecls def collectUsedDecls (env : Environment) (decl : Decl) (used : NameSet := {}) : NameSet := (CollectUsedDecls.collectDecl decl env).run' used abbrev VarTypeMap := HashMap VarId IRType abbrev JPParamsMap := HashMap JoinPointId (Array Param) namespace CollectMaps abbrev Collector := (VarTypeMap × JPParamsMap) → (VarTypeMap × JPParamsMap) @[inline] def collectVar (x : VarId) (t : IRType) : Collector | (vs, js) := (vs.insert x t, js) def collectParams (ps : Array Param) : Collector := fun s => ps.foldl (fun s p => collectVar p.x p.ty s) s @[inline] def collectJP (j : JoinPointId) (xs : Array Param) : Collector | (vs, js) := (vs, js.insert j xs) /- `collectFnBody` assumes the variables in -/ partial def collectFnBody : FnBody → Collector | (FnBody.vdecl x t _ b) := collectVar x t ∘ collectFnBody b | (FnBody.jdecl j xs v b) := collectJP j xs ∘ collectParams xs ∘ collectFnBody v ∘ collectFnBody b | (FnBody.case _ _ alts) := fun s => alts.foldl (fun s alt => collectFnBody alt.body s) s | e := if e.isTerminal then id else collectFnBody e.body def collectDecl : Decl → Collector | (Decl.fdecl _ xs _ b) := collectParams xs ∘ collectFnBody b | _ := id end CollectMaps /- Return a pair `(v, j)`, where `v` is a mapping from variable/parameter to type, and `j` is a mapping from join point to parameters. This function assumes `d` has normalized indexes (see `normids.lean`). -/ def mkVarJPMaps (d : Decl) : VarTypeMap × JPParamsMap := CollectMaps.collectDecl d ({}, {}) end IR end Lean