Skip to content

Commit c5b0e59

Browse files
author
DigitalCodeCrafter
committed
added some passes over the MIR
1 parent aea06a8 commit c5b0e59

10 files changed

Lines changed: 311 additions & 23 deletions

File tree

src/main.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use ksi::{backend, common::diagnostics::sinks::Diagnostics, mir::{self, pretty}, semantics, syntax};
1+
use ksi::{backend, common::diagnostics::sinks::Diagnostics, mir::{self, passes::{ConstPropagation, CopyPropagation, DeadLocalElim, Pass, run_passes}, pretty}, semantics, syntax};
22

33

44
fn main() -> Result<(), ()> {
@@ -14,9 +14,15 @@ fn main() -> Result<(), ()> {
1414
return Err(());
1515
}
1616

17-
let prog_ir = mir::lower(typed_ast, &symbols, &mut diagnostics);
17+
let mut prog_ir = mir::lower(typed_ast, &symbols, &mut diagnostics);
1818

19-
mir::verify_ir(&prog_ir)?;
19+
let mut passes: Vec<Box<dyn Pass>> = vec![
20+
Box::new(CopyPropagation),
21+
Box::new(ConstPropagation),
22+
Box::new(DeadLocalElim)
23+
];
24+
25+
run_passes(&mut prog_ir, &mut passes);
2026

2127
let out = backend::emit(&prog_ir, &mut diagnostics);
2228

src/mir/lowerer.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ pub fn lower(typed_ast: t::TypedAst, symbols: &SymbolTable, _diagnostics: &mut i
1010
}
1111

1212
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13-
pub struct LocalId(u32);
13+
pub struct LocalId(pub(super) u32);
1414
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15-
pub struct BlockId(u32);
15+
pub struct BlockId(pub(super) u32);
1616

1717
impl LocalId {
1818
pub fn index(&self) -> u32 { self.0 }
@@ -69,8 +69,8 @@ impl MirBuilder<'_> {
6969
let symbol = self.symbols.get(sym);
7070
let local = self.new_local(symbol.ty.clone().expect("[Lowerer] Internal Error: local var symbol has no type annotation"));
7171
self.env.insert(sym, local);
72-
self.emit(Instr::Debug(DebugInfo { span: stmt.span, kind: DebugKind::DeclareLocal { local, name: symbol.name.clone() } }));
7372
self.lower_expr(Place { local, projection: Vec::new() }, value);
73+
self.emit(Instr::Debug(DebugInfo { span: stmt.span, kind: DebugKind::DeclareLocal { local, name: symbol.name.clone() } }));
7474
}
7575
t::StmtKind::Expr(expr) => {
7676
let unused = Place { local: self.new_local(expr.ty.clone()), projection: Vec::new() };
@@ -82,7 +82,6 @@ impl MirBuilder<'_> {
8282
}
8383

8484
fn lower_expr(&mut self, dest: Place, expr: t::Expr) {
85-
self.emit(Instr::Debug(DebugInfo { span: expr.span, kind: DebugKind::EnterExpr }));
8685
let rval = match expr.kind {
8786
t::ExprKind::Number { value, .. } => RValue::Use(Operand::Const(Const::Number(value))),
8887

@@ -101,21 +100,23 @@ impl MirBuilder<'_> {
101100
}
102101

103102
t::ExprKind::Block { stmts, tail_expr } => {
103+
self.emit(Instr::Debug(DebugInfo { span: expr.span, kind: DebugKind::EnterScope }));
104104
for stmt in stmts {
105105
self.lower_stmt(stmt);
106106
}
107107

108+
self.emit(Instr::Debug(DebugInfo { span: expr.span, kind: DebugKind::ExitScope }));
109+
108110
match tail_expr {
109111
Some(expr) => return self.lower_expr(dest, *expr),
110-
None => RValue::Use(Operand::Const(Const::Unit)),
112+
None => RValue::Use(Operand::Const(Const::Unit))
111113
}
112114
}
113115

114116
t::ExprKind::Error => RValue::Poison,
115117
};
116118

117119
self.emit(Instr::Assign(dest, rval));
118-
self.emit(Instr::Debug(DebugInfo { span: expr.span, kind: DebugKind::ExitExpr }));
119120
}
120121
}
121122

src/mir/mir.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,18 @@ pub enum Operand {
4545
Const(Const),
4646
}
4747

48-
#[derive(Debug, Clone, PartialEq)]
48+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4949
pub struct Place {
5050
pub local: LocalId,
5151
pub projection: Vec<Projection>,
5252
}
5353

54-
#[derive(Debug, Clone, PartialEq)]
54+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5555
pub enum Projection {
5656

5757
}
5858

59-
#[derive(Debug, PartialEq)]
59+
#[derive(Debug, PartialEq, Clone)]
6060
pub enum Const {
6161
Number(f64),
6262
Unit,
@@ -70,8 +70,8 @@ pub struct DebugInfo {
7070

7171
#[derive(Debug, PartialEq)]
7272
pub enum DebugKind {
73-
EnterExpr,
74-
ExitExpr,
73+
EnterScope,
74+
ExitScope,
7575
DeclareLocal {
7676
local: LocalId,
7777
name: String,

src/mir/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
mod mir;
22
mod lowerer;
3-
mod verifier;
43
pub mod pretty;
4+
mod verifier;
5+
pub mod passes;
56

67
pub use mir::*;
78
pub use lowerer::{BlockId, LocalId};
89
pub use lowerer::lower;
9-
pub use verifier::verify_ir;

src/mir/passes/const_prop.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use std::collections::HashMap;
2+
3+
use crate::mir::{Block, Const, Instr, LocalId, Operand, RValue, Terminator, passes::Pass};
4+
5+
6+
pub struct ConstPropagation;
7+
8+
impl Pass for ConstPropagation {
9+
fn name(&self) -> &'static str { "constant-propagation" }
10+
11+
fn run(&mut self, body: &mut crate::mir::Body) {
12+
let mut const_map = HashMap::new();
13+
for block in &mut body.blocks {
14+
const_map.clear();
15+
propagate_in_block(&mut const_map, block);
16+
}
17+
}
18+
}
19+
20+
fn propagate_in_block(const_map: &mut HashMap<LocalId, Const>, block: &mut Block) {
21+
for instr in &mut block.instrs {
22+
prop_in_instr(const_map, instr);
23+
}
24+
prop_in_terminator(const_map, &mut block.terminator);
25+
}
26+
27+
fn prop_in_instr(const_map: &mut HashMap<LocalId, Const>, instr: &mut Instr) {
28+
match instr {
29+
Instr::Assign(place, RValue::Use(Operand::Const(constant))) => {
30+
const_map.insert(place.local, constant.clone());
31+
}
32+
33+
Instr::Assign(place, rval) => {
34+
prop_in_rval(const_map, rval);
35+
const_map.remove(&place.local);
36+
}
37+
38+
Instr::Debug(_) => {},
39+
}
40+
}
41+
42+
fn prop_in_rval(const_map: &HashMap<LocalId, Const>, rval: &mut RValue) {
43+
match rval {
44+
RValue::Use(op) => prop_in_operand(const_map, op),
45+
RValue::Binary(_, lhs, rhs) => {
46+
prop_in_operand(const_map, lhs);
47+
prop_in_operand(const_map, rhs);
48+
}
49+
RValue::Poison => {},
50+
}
51+
}
52+
53+
fn prop_in_operand(const_map: &HashMap<LocalId, Const>, op: &mut Operand) {
54+
let local = match op {
55+
Operand::Copy(place) |
56+
Operand::Move(place) => &place.local,
57+
_ => return,
58+
};
59+
60+
if let Some(constant) = const_map.get(local) {
61+
*op = Operand::Const(constant.clone());
62+
}
63+
}
64+
65+
fn prop_in_terminator(const_map: &HashMap<LocalId, Const>, term: &mut Terminator) {
66+
match term {
67+
Terminator::Goto(_) => {},
68+
Terminator::Return(op) => prop_in_operand(const_map, op),
69+
Terminator::Unreachable => {},
70+
}
71+
}
72+
73+

src/mir/passes/copy_prop.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use std::collections::HashMap;
2+
3+
use crate::mir::{Block, Instr, LocalId, Operand, Place, RValue, Terminator, passes::Pass};
4+
5+
6+
pub struct CopyPropagation;
7+
impl Pass for CopyPropagation {
8+
fn name(&self) -> &'static str { "copy-propagation" }
9+
10+
fn run(&mut self, body: &mut crate::mir::Body) {
11+
let mut copy_map = HashMap::new();
12+
for block in &mut body.blocks {
13+
copy_map.clear();
14+
propagate_in_block(&mut copy_map, block);
15+
}
16+
}
17+
}
18+
19+
fn propagate_in_block(copy_map: &mut HashMap<LocalId, LocalId>, block: &mut Block) {
20+
for instr in &mut block.instrs {
21+
prop_in_instr(copy_map, instr);
22+
}
23+
prop_in_terminator(copy_map, &mut block.terminator);
24+
}
25+
26+
fn prop_in_instr(copy_map: &mut HashMap<LocalId, LocalId>, instr: &mut Instr) {
27+
match instr {
28+
Instr::Assign(place, RValue::Use(Operand::Copy(src))) => {
29+
copy_map.insert(place.local, src.local);
30+
}
31+
32+
Instr::Assign(place, rval) => {
33+
prop_in_rval(copy_map, rval);
34+
copy_map.remove(&place.local);
35+
}
36+
37+
Instr::Debug(_) => {},
38+
}
39+
}
40+
41+
fn prop_in_rval(copy_map: &HashMap<LocalId, LocalId>, rval: &mut RValue) {
42+
match rval {
43+
RValue::Use(op) => prop_in_operand(copy_map, op),
44+
RValue::Binary(_, lhs, rhs) => {
45+
prop_in_operand(copy_map, lhs);
46+
prop_in_operand(copy_map, rhs);
47+
}
48+
RValue::Poison => {},
49+
}
50+
}
51+
52+
fn prop_in_operand(copy_map: &HashMap<LocalId, LocalId>, op: &mut Operand) {
53+
let local = match op {
54+
Operand::Copy(place) |
55+
Operand::Move(place) => &place.local,
56+
_ => return,
57+
};
58+
59+
if let Some(src) = copy_map.get(local) {
60+
*op = Operand::Copy(Place { local: *src, projection: Vec::new() });
61+
}
62+
}
63+
64+
fn prop_in_terminator(copy_map: &HashMap<LocalId, LocalId>, term: &mut Terminator) {
65+
match term {
66+
Terminator::Goto(_) => {},
67+
Terminator::Return(op) => prop_in_operand(copy_map, op),
68+
Terminator::Unreachable => {},
69+
}
70+
}

src/mir/passes/dead_local_elim.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
use std::collections::HashSet;
2+
use crate::mir::{Block, DebugKind, Instr, LocalId, Operand, Place, RValue, passes::Pass};
3+
4+
5+
pub struct DeadLocalElim;
6+
7+
impl Pass for DeadLocalElim {
8+
fn name(&self) -> &'static str { "dead-local-elimination" }
9+
10+
fn run(&mut self, body: &mut crate::mir::Body) {
11+
let mut used = HashSet::new();
12+
for block in &mut body.blocks {
13+
find_live_in_block(&mut used, block);
14+
}
15+
16+
let mut remap = vec![None; body.locals.len()];
17+
let mut new_locals = Vec::with_capacity(used.len());
18+
for (old_idx, local) in body.locals.drain(..).enumerate() {
19+
let old_id = LocalId(old_idx as u32);
20+
if used.contains(&old_id) {
21+
let new_idx = new_locals.len();
22+
new_locals.push(local);
23+
remap[old_idx] = Some(LocalId(new_idx as u32));
24+
}
25+
}
26+
body.locals = new_locals;
27+
28+
for block in &mut body.blocks {
29+
remap_in_block(&remap, block);
30+
}
31+
}
32+
}
33+
34+
fn find_live_in_block(used: &mut HashSet<LocalId>, block: &Block) {
35+
for instr in &block.instrs {
36+
match instr {
37+
Instr::Assign(_, rval) => {
38+
find_live_in_rval(used, rval);
39+
}
40+
Instr::Debug(info) => {
41+
if let DebugKind::DeclareLocal { local, .. } = info.kind {
42+
used.insert(local);
43+
}
44+
}
45+
}
46+
}
47+
}
48+
49+
fn find_live_in_rval(used: &mut HashSet<LocalId>, rval: &RValue) {
50+
match rval {
51+
RValue::Use(op) => find_live_in_op(used, op),
52+
RValue::Binary(_, lhs, rhs) => {
53+
find_live_in_op(used, lhs);
54+
find_live_in_op(used, rhs);
55+
}
56+
RValue::Poison => {},
57+
}
58+
}
59+
60+
fn find_live_in_op(used: &mut HashSet<LocalId>, op: &Operand) {
61+
match op {
62+
Operand::Copy(place) |
63+
Operand::Move(place) => {
64+
used.insert(place.local);
65+
}
66+
Operand::Const(_) => {},
67+
}
68+
}
69+
70+
fn remap_in_block(remap: &[Option<LocalId>], block: &mut Block) {
71+
block.instrs.retain_mut(|instr| {
72+
match instr {
73+
Instr::Assign(place, rval) => {
74+
remap_in_rval(remap, rval);
75+
remap_place(remap, place)
76+
}
77+
Instr::Debug(info) => {
78+
if let DebugKind::DeclareLocal { local, .. } = &mut info.kind {
79+
if let Some(new) = remap[local.index() as usize] {
80+
*local = new;
81+
}
82+
}
83+
true
84+
}
85+
}
86+
});
87+
}
88+
89+
fn remap_in_rval(remap: &[Option<LocalId>], rval: &mut RValue) {
90+
match rval {
91+
RValue::Use(op) => remap_in_op(remap, op),
92+
RValue::Binary(_, lhs, rhs) => {
93+
remap_in_op(remap, lhs);
94+
remap_in_op(remap, rhs);
95+
}
96+
RValue::Poison => {},
97+
}
98+
}
99+
100+
fn remap_in_op(remap: &[Option<LocalId>], op: &mut Operand) {
101+
match op {
102+
Operand::Copy(place) |
103+
Operand::Move(place) => {
104+
remap_place(remap, place);
105+
}
106+
Operand::Const(_) => {},
107+
}
108+
}
109+
110+
fn remap_place(remap: &[Option<LocalId>], place: &mut Place) -> bool {
111+
if let Some(new) = remap[place.local.index() as usize] {
112+
place.local = new;
113+
return true;
114+
}
115+
false
116+
}

0 commit comments

Comments
 (0)