82 lines
3.5 KiB
Text
82 lines
3.5 KiB
Text
/-
|
||
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
|