lean4-htt/library/init/lean/ir/elim_phi.lean
Leonardo de Moura af1a5fe874 feat(library/init/lean/ir): add x : ty := y instruction
It is useful when we are not producing IR in SSA.
2018-05-17 15:44:13 -07:00

82 lines
3.5 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2018 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import init.lean.ir.instances init.control.state init.lean.disjoint_set
namespace lean
namespace ir
/-
We need to eliminate Phi nodes before we translate the IR to C/C++.
The procedure is the following. First, for each instruction `x : ty := phi y_1 ... y_n`,
we put `x`, `y_1`, ... `y_n` in the same equivalence class.
Then, we select a representative from each equivalence class and replace each
variable with its representative.
-/
@[reducible] def elim_phi_m (α : Type) := state_t (disjoint_set var) id α
def elim_phi_m.run {α} (a : elim_phi_m α) : α :=
run a (mk_disjoint_set var)
def merge (x y : var) : elim_phi_m unit :=
modify $ λ s, s.merge x y
def find (x : var) : elim_phi_m var :=
do s ← get, return $ s.find x
def group_vars : decl → elim_phi_m unit
| (decl.defn _ bs) := bs.mfor $ λ b, b.phis.mfor $ λ p, p.ys.mfor (merge p.x)
| _ := return ()
def instr.replace_vars : instr → elim_phi_m instr
| (instr.assign x ty y) := instr.assign <$> find x <*> pure ty <*> find y
| (instr.assign_lit x ty lit) := instr.assign_lit <$> find x <*> pure ty <*> pure lit
| (instr.assign_unop x ty op y) := instr.assign_unop <$> find x <*> pure ty <*> pure op <*> find y
| (instr.assign_binop x ty op y z) := instr.assign_binop <$> find x <*> pure ty <*> pure op <*> find y <*> find z
| (instr.unop op x) := instr.unop op <$> find x
| (instr.call xs f ys) := instr.call <$> xs.mmap find <*> pure f <*> ys.mmap find
| (instr.cnstr o tag n s) := instr.cnstr <$> find o <*> pure tag <*> pure n <*> pure s
| (instr.set o i x) := instr.set <$> find o <*> pure i <*> find x
| (instr.get x o i) := instr.get <$> find x <*> find o <*> pure i
| (instr.sset o i x) := instr.sset <$> find o <*> pure i <*> find x
| (instr.sget x ty o i) := instr.sget <$> find x <*> pure ty <*> find o <*> pure i
| (instr.closure x f ys) := instr.closure <$> find x <*> pure f <*> ys.mmap find
| (instr.apply x ys) := instr.apply <$> find x <*> ys.mmap find
| (instr.array a sz c) := instr.array <$> find a <*> find sz <*> find c
| (instr.array_write a i v) := instr.array_write <$> find a <*> find i <*> find v
| (instr.sarray a ty sz c) := instr.sarray <$> find a <*> pure ty <*> find sz <*> find c
def terminator.replace_vars : terminator → elim_phi_m terminator
| (terminator.ret xs) := terminator.ret <$> xs.mmap find
| (terminator.case x bs) := terminator.case <$> find x <*> pure bs
| j@(terminator.jmp _) := pure j
def arg.replace_vars (a : arg) : elim_phi_m arg :=
do x ← find a.n, return { n := x, ..a }
def header.replace_vars (h : header) : elim_phi_m header :=
do as ← h.args.mmap arg.replace_vars, return { args := as, ..h }
def block.replace_vars (b : block) : elim_phi_m block :=
do instrs' ← b.instrs.mmap instr.replace_vars,
term' ← b.term.replace_vars,
return
{ phis := [],
instrs := instrs',
term := term', ..b}
def decl.replace_vars : decl → elim_phi_m decl
| (decl.defn h bs) := decl.defn <$> (header.replace_vars h) <*> bs.mmap block.replace_vars
| other := pure other
def elim_phi_aux (d : decl) : elim_phi_m decl :=
group_vars d >> d.replace_vars
def elim_phi (d : decl) : decl :=
(elim_phi_aux d).run
end ir
end lean