Skip to content

Commit b11842a

Browse files
committed
Teach propagate optimisation about break/return/block jumping
1 parent f7a1301 commit b11842a

File tree

5 files changed

+222
-95
lines changed

5 files changed

+222
-95
lines changed

Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,8 @@ default-members = [
1414
"source-compiler",
1515
]
1616

17+
# Code is generally not exception-safe, so we do not want to catch any panics
18+
1719
[profile.release]
1820
lto = true
21+
panic = "abort"

lib-ir/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ pub enum ExprKind {
220220
}, // jumps to the end of an enclosing Block or the beginning of an enclosing Loop; Break is noreturn
221221
Block {
222222
expr: Box<Expr>,
223-
}, // Jump target for Break; type must be at least as wide as expr.vartype and all Breaks that target this block
223+
}, // Jump landing for Break; type must be at least as wide as expr.vartype and all Breaks that target this block
224224
Sequence {
225225
content: Vec<Expr>,
226226
}, // returns the value of the last expression, or `undefined` if there are zero expressions

lib-ir/src/opt/landing_context.rs

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use super::union_type;
2+
use crate::VarType;
3+
4+
// List of current unioned types of return and break
5+
// the content[0] is for returns (and breaks that end the function)
6+
pub struct LandingContext {
7+
content: Vec<(usize, Option<VarType>)>, // pair(new index, current union)
8+
num_new: usize,
9+
}
10+
11+
impl LandingContext {
12+
pub fn for_new_func() -> Self {
13+
Self {
14+
content: vec![(0, None)],
15+
num_new: 1,
16+
}
17+
}
18+
pub fn with_landing<R, F: FnOnce(&mut Self) -> R>(&mut self, f: F) -> (R, Option<VarType>) {
19+
self.content.push((self.num_new, None));
20+
self.num_new += 1;
21+
let ret = f(self);
22+
self.num_new -= 1;
23+
(ret, self.content.pop().unwrap().1)
24+
}
25+
26+
pub fn skip_new_landing<R, F: FnOnce(&mut Self) -> R>(&mut self, f: F) -> R {
27+
self.num_new += 1;
28+
let ret = f(self);
29+
self.num_new -= 1;
30+
ret
31+
}
32+
33+
// will panic if num_frames is out of range
34+
// returns new num_frames to use
35+
pub fn add_break(&mut self, num_frames: usize, vartype: VarType) -> usize {
36+
let idx = self.content.len() - 1 - num_frames;
37+
let landing_ref = &mut self.content[idx];
38+
landing_ref.1 = union_type(landing_ref.1, Some(vartype));
39+
let new_idx = self.num_new - 1 - landing_ref.0;
40+
new_idx
41+
}
42+
pub fn add_return(&mut self, vartype: VarType) {
43+
let landing_ref = &mut self.content[0];
44+
landing_ref.1 = union_type(landing_ref.1, Some(vartype));
45+
}
46+
}

lib-ir/src/opt/mod.rs

+32
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod landing_context;
12
mod propagate;
23
mod relabeller;
34
mod typecast;
@@ -55,3 +56,34 @@ pub fn optimize_all(mut program: Program) -> Program {
5556
}
5657
program
5758
}
59+
60+
/**
61+
* Returns the type wide enough to contain both the given two types.
62+
*/
63+
fn union_type(first: Option<VarType>, second: Option<VarType>) -> Option<VarType> {
64+
if first.is_none() {
65+
return second;
66+
}
67+
if second.is_none() {
68+
return first;
69+
}
70+
// now both first and second are not None
71+
let u_first = first.unwrap();
72+
let u_second = second.unwrap();
73+
if u_first == u_second {
74+
return Some(u_first);
75+
}
76+
Some(VarType::Any)
77+
}
78+
79+
/**
80+
* Helper function that returns true if dest got changed
81+
*/
82+
fn useful_update<T: Eq>(dest: &mut T, source: T) -> bool {
83+
if *dest == source {
84+
false
85+
} else {
86+
*dest = source;
87+
true
88+
}
89+
}

0 commit comments

Comments
 (0)