cleanup
This commit is contained in:
parent
047e1ed15c
commit
9c32f260a1
678
lang/src/son.rs
678
lang/src/son.rs
|
@ -49,6 +49,24 @@ impl crate::ctx_map::CtxEntry for Nid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! inference {
|
||||||
|
($ty:ident, $ctx:expr, $self:expr, $pos:expr, $subject:literal, $example:literal) => {
|
||||||
|
let Some($ty) = $ctx.ty else {
|
||||||
|
$self.report(
|
||||||
|
$pos,
|
||||||
|
concat!(
|
||||||
|
"resulting ",
|
||||||
|
$subject,
|
||||||
|
" cannot be inferred from context, consider using `",
|
||||||
|
$example,
|
||||||
|
"` to hint the type",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return Value::NEVER;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct Nodes {
|
struct Nodes {
|
||||||
values: Vec<Result<Node, (Nid, debug::Trace)>>,
|
values: Vec<Result<Node, (Nid, debug::Trace)>>,
|
||||||
|
@ -69,6 +87,287 @@ impl Default for Nodes {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Nodes {
|
impl Nodes {
|
||||||
|
fn loop_depth(&mut self, target: Nid) -> LoopDepth {
|
||||||
|
if self[target].loop_depth != 0 {
|
||||||
|
return self[target].loop_depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
self[target].loop_depth = match self[target].kind {
|
||||||
|
Kind::Entry | Kind::Then | Kind::Else | Kind::Call { .. } | Kind::Return | Kind::If => {
|
||||||
|
let dpth = self.loop_depth(self[target].inputs[0]);
|
||||||
|
if self[target].loop_depth != 0 {
|
||||||
|
return self[target].loop_depth;
|
||||||
|
}
|
||||||
|
dpth
|
||||||
|
}
|
||||||
|
Kind::Region => {
|
||||||
|
let l = self.loop_depth(self[target].inputs[0]);
|
||||||
|
let r = self.loop_depth(self[target].inputs[1]);
|
||||||
|
debug_assert_eq!(l, r);
|
||||||
|
l
|
||||||
|
}
|
||||||
|
Kind::Loop => {
|
||||||
|
let depth = Self::loop_depth(self, self[target].inputs[0]) + 1;
|
||||||
|
self[target].loop_depth = depth;
|
||||||
|
let mut cursor = self[target].inputs[1];
|
||||||
|
while cursor != target {
|
||||||
|
self[cursor].loop_depth = depth;
|
||||||
|
let next = if self[cursor].kind == Kind::Region {
|
||||||
|
self.loop_depth(self[cursor].inputs[0]);
|
||||||
|
self[cursor].inputs[1]
|
||||||
|
} else {
|
||||||
|
self.idom(cursor)
|
||||||
|
};
|
||||||
|
debug_assert_ne!(next, VOID);
|
||||||
|
if matches!(self[cursor].kind, Kind::Then | Kind::Else) {
|
||||||
|
let other = *self[next]
|
||||||
|
.outputs
|
||||||
|
.iter()
|
||||||
|
.find(|&&n| self[n].kind != self[cursor].kind)
|
||||||
|
.unwrap();
|
||||||
|
if self[other].loop_depth == 0 {
|
||||||
|
self[other].loop_depth = depth - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor = next;
|
||||||
|
}
|
||||||
|
depth
|
||||||
|
}
|
||||||
|
Kind::Start | Kind::End => 1,
|
||||||
|
u => unreachable!("{u:?}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
self[target].loop_depth
|
||||||
|
}
|
||||||
|
|
||||||
|
fn idepth(&mut self, target: Nid) -> IDomDepth {
|
||||||
|
if target == VOID {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if self[target].depth == 0 {
|
||||||
|
self[target].depth = match self[target].kind {
|
||||||
|
Kind::End | Kind::Start => unreachable!("{:?}", self[target].kind),
|
||||||
|
Kind::Region => {
|
||||||
|
self.idepth(self[target].inputs[0]).max(self.idepth(self[target].inputs[1]))
|
||||||
|
}
|
||||||
|
_ => self.idepth(self[target].inputs[0]),
|
||||||
|
} + 1;
|
||||||
|
}
|
||||||
|
self[target].depth
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fix_loops(&mut self) {
|
||||||
|
'o: for l in self[LOOPS].outputs.clone() {
|
||||||
|
let mut cursor = self[l].inputs[1];
|
||||||
|
while cursor != l {
|
||||||
|
if self[cursor].kind == Kind::If
|
||||||
|
&& self[cursor]
|
||||||
|
.outputs
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.any(|b| self.loop_depth(b) < self.loop_depth(cursor))
|
||||||
|
{
|
||||||
|
continue 'o;
|
||||||
|
}
|
||||||
|
cursor = self.idom(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
self[l].outputs.push(NEVER);
|
||||||
|
self[NEVER].inputs.push(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_up_impl(&mut self, node: Nid) {
|
||||||
|
if !self.visited.set(node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 1..self[node].inputs.len() {
|
||||||
|
let inp = self[node].inputs[i];
|
||||||
|
if !self[inp].kind.is_pinned() {
|
||||||
|
self.push_up_impl(inp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self[node].kind.is_pinned() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut deepest = VOID;
|
||||||
|
for i in 1..self[node].inputs.len() {
|
||||||
|
let inp = self[node].inputs[i];
|
||||||
|
if self.idepth(inp) > self.idepth(deepest) {
|
||||||
|
deepest = self.idom(inp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if deepest == VOID {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let index = self[0].outputs.iter().position(|&p| p == node).unwrap();
|
||||||
|
self[0].outputs.remove(index);
|
||||||
|
self[node].inputs[0] = deepest;
|
||||||
|
debug_assert!(
|
||||||
|
!self[deepest].outputs.contains(&node)
|
||||||
|
|| matches!(self[deepest].kind, Kind::Call { .. }),
|
||||||
|
"{node} {:?} {deepest} {:?}",
|
||||||
|
self[node],
|
||||||
|
self[deepest]
|
||||||
|
);
|
||||||
|
self[deepest].outputs.push(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_rpo(&mut self, node: Nid, rpo: &mut Vec<Nid>) {
|
||||||
|
if !self.is_cfg(node) || !self.visited.set(node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..self[node].outputs.len() {
|
||||||
|
self.collect_rpo(self[node].outputs[i], rpo);
|
||||||
|
}
|
||||||
|
rpo.push(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_up(&mut self, rpo: &mut Vec<Nid>) {
|
||||||
|
rpo.clear();
|
||||||
|
self.collect_rpo(VOID, rpo);
|
||||||
|
|
||||||
|
for &node in rpo.iter().rev() {
|
||||||
|
self.loop_depth(node);
|
||||||
|
for i in 0..self[node].inputs.len() {
|
||||||
|
self.push_up_impl(self[node].inputs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches!(self[node].kind, Kind::Loop | Kind::Region) {
|
||||||
|
for i in 0..self[node].outputs.len() {
|
||||||
|
let usage = self[node].outputs[i];
|
||||||
|
if self[usage].kind == Kind::Phi {
|
||||||
|
self.push_up_impl(usage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_assert_eq!(
|
||||||
|
self.iter()
|
||||||
|
.map(|(n, _)| n)
|
||||||
|
.filter(|&n| !self.visited.get(n)
|
||||||
|
&& !matches!(self[n].kind, Kind::Arg | Kind::Mem | Kind::Loops))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
vec![],
|
||||||
|
"{:?}",
|
||||||
|
self.iter()
|
||||||
|
.filter(|&(n, nod)| !self.visited.get(n)
|
||||||
|
&& !matches!(nod.kind, Kind::Arg | Kind::Mem | Kind::Loops))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn better(&mut self, is: Nid, then: Nid) -> bool {
|
||||||
|
debug_assert_ne!(self.idepth(is), self.idepth(then), "{is} {then}");
|
||||||
|
self.loop_depth(is) < self.loop_depth(then)
|
||||||
|
|| self.idepth(is) > self.idepth(then)
|
||||||
|
|| self[then].kind == Kind::If
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_forward_edge(&mut self, usage: Nid, def: Nid) -> bool {
|
||||||
|
match self[usage].kind {
|
||||||
|
Kind::Phi => {
|
||||||
|
self[usage].inputs[2] != def || self[self[usage].inputs[0]].kind != Kind::Loop
|
||||||
|
}
|
||||||
|
Kind::Loop => self[usage].inputs[1] != def,
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_down(&mut self, node: Nid) {
|
||||||
|
if !self.visited.set(node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for usage in self[node].outputs.clone() {
|
||||||
|
if self.is_forward_edge(usage, node) && self[node].kind == Kind::Stre {
|
||||||
|
self.push_down(usage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for usage in self[node].outputs.clone() {
|
||||||
|
if self.is_forward_edge(usage, node) {
|
||||||
|
self.push_down(usage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self[node].kind.is_pinned() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut min = None::<Nid>;
|
||||||
|
for i in 0..self[node].outputs.len() {
|
||||||
|
let usage = self[node].outputs[i];
|
||||||
|
let ub = self.use_block(node, usage);
|
||||||
|
min = min.map(|m| self.common_dom(ub, m)).or(Some(ub));
|
||||||
|
}
|
||||||
|
let mut min = min.unwrap();
|
||||||
|
|
||||||
|
debug_assert!(self.dominates(self[node].inputs[0], min));
|
||||||
|
|
||||||
|
let mut cursor = min;
|
||||||
|
while cursor != self[node].inputs[0] {
|
||||||
|
cursor = self.idom(cursor);
|
||||||
|
if self.better(cursor, min) {
|
||||||
|
min = cursor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self[min].kind.ends_basic_block() {
|
||||||
|
min = self.idom(min);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.check_dominance(node, min, true);
|
||||||
|
|
||||||
|
let prev = self[node].inputs[0];
|
||||||
|
debug_assert!(self.idepth(min) >= self.idepth(prev));
|
||||||
|
let index = self[prev].outputs.iter().position(|&p| p == node).unwrap();
|
||||||
|
self[prev].outputs.remove(index);
|
||||||
|
self[node].inputs[0] = min;
|
||||||
|
self[min].outputs.push(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn use_block(&mut self, target: Nid, from: Nid) -> Nid {
|
||||||
|
if self[from].kind != Kind::Phi {
|
||||||
|
return self.idom(from);
|
||||||
|
}
|
||||||
|
|
||||||
|
let index = self[from].inputs.iter().position(|&n| n == target).unwrap();
|
||||||
|
self[self[from].inputs[0]].inputs[index - 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn idom(&mut self, target: Nid) -> Nid {
|
||||||
|
match self[target].kind {
|
||||||
|
Kind::Start => VOID,
|
||||||
|
Kind::End => unreachable!(),
|
||||||
|
Kind::Region => {
|
||||||
|
let &[lcfg, rcfg] = self[target].inputs.as_slice() else { unreachable!() };
|
||||||
|
self.common_dom(lcfg, rcfg)
|
||||||
|
}
|
||||||
|
_ => self[target].inputs[0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn common_dom(&mut self, mut a: Nid, mut b: Nid) -> Nid {
|
||||||
|
while a != b {
|
||||||
|
let [ldepth, rdepth] = [self.idepth(a), self.idepth(b)];
|
||||||
|
if ldepth >= rdepth {
|
||||||
|
a = self.idom(a);
|
||||||
|
}
|
||||||
|
if ldepth <= rdepth {
|
||||||
|
b = self.idom(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
fn merge_scopes(
|
fn merge_scopes(
|
||||||
&mut self,
|
&mut self,
|
||||||
loops: &mut [Loop],
|
loops: &mut [Loop],
|
||||||
|
@ -166,12 +465,12 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gcm(&mut self) {
|
fn gcm(&mut self, rpo: &mut Vec<Nid>) {
|
||||||
fix_loops(self);
|
self.fix_loops();
|
||||||
self.visited.clear(self.values.len());
|
self.visited.clear(self.values.len());
|
||||||
push_up(self);
|
self.push_up(rpo);
|
||||||
self.visited.clear(self.values.len());
|
self.visited.clear(self.values.len());
|
||||||
push_down(self, VOID);
|
self.push_down(VOID);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
|
@ -471,7 +770,7 @@ impl Nodes {
|
||||||
break ty::Id::LEFT_UNREACHABLE;
|
break ty::Id::LEFT_UNREACHABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor = idom(self, cursor);
|
cursor = self.idom(cursor);
|
||||||
};
|
};
|
||||||
|
|
||||||
return Some(self.new_node_nop(ty, K::If, [ctrl, cond]));
|
return Some(self.new_node_nop(ty, K::If, [ctrl, cond]));
|
||||||
|
@ -861,7 +1160,7 @@ impl Nodes {
|
||||||
|
|
||||||
let node = self[nd].clone();
|
let node = self[nd].clone();
|
||||||
for &i in node.inputs.iter() {
|
for &i in node.inputs.iter() {
|
||||||
let dom = idom(self, i);
|
let dom = self.idom(i);
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
self.dominates(dom, min),
|
self.dominates(dom, min),
|
||||||
"{dom} {min} {node:?} {:?}",
|
"{dom} {min} {node:?} {:?}",
|
||||||
|
@ -870,7 +1169,7 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
if check_outputs {
|
if check_outputs {
|
||||||
for &o in node.outputs.iter() {
|
for &o in node.outputs.iter() {
|
||||||
let dom = use_block(nd, o, self);
|
let dom = self.use_block(nd, o);
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
self.dominates(min, dom),
|
self.dominates(min, dom),
|
||||||
"{min} {dom} {node:?} {:?}",
|
"{min} {dom} {node:?} {:?}",
|
||||||
|
@ -886,11 +1185,11 @@ impl Nodes {
|
||||||
break true;
|
break true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if idepth(self, dominator) > idepth(self, dominated) {
|
if self.idepth(dominator) > self.idepth(dominated) {
|
||||||
break false;
|
break false;
|
||||||
}
|
}
|
||||||
|
|
||||||
dominated = idom(self, dominated);
|
dominated = self.idom(dominated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1577,12 +1876,7 @@ impl<'a> Codegen<'a> {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ci.emit_ct_body(
|
self.ci.emit_ct_body(self.tys, self.files, Sig { args: Tuple::empty(), ret }, self.pool);
|
||||||
self.tys,
|
|
||||||
self.files,
|
|
||||||
Sig { args: Tuple::empty(), ret },
|
|
||||||
&mut self.pool.ralloc,
|
|
||||||
);
|
|
||||||
|
|
||||||
let func = Func {
|
let func = Func {
|
||||||
file,
|
file,
|
||||||
|
@ -1711,18 +2005,11 @@ impl<'a> Codegen<'a> {
|
||||||
self.raw_expr_ctx(expr, Ctx::default())
|
self.raw_expr_ctx(expr, Ctx::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn raw_expr_ctx(&mut self, expr: &Expr, ctx: Ctx) -> Option<Value> {
|
fn raw_expr_ctx(&mut self, expr: &Expr, mut ctx: Ctx) -> Option<Value> {
|
||||||
// ordered by complexity of the expression
|
// ordered by complexity of the expression
|
||||||
match *expr {
|
match *expr {
|
||||||
Expr::Null { pos } => {
|
Expr::Null { pos } => {
|
||||||
let Some(ty) = ctx.ty else {
|
inference!(ty, ctx, self, pos, "null pointer", "@as(^<ty>, null)");
|
||||||
self.report(
|
|
||||||
pos,
|
|
||||||
"resulting pointer cannot be inferred from context, \
|
|
||||||
consider using `@as(^<ty>, null)` to hint the type",
|
|
||||||
);
|
|
||||||
return Value::NEVER;
|
|
||||||
};
|
|
||||||
|
|
||||||
if !ty.is_pointer() {
|
if !ty.is_pointer() {
|
||||||
self.report(
|
self.report(
|
||||||
|
@ -1739,14 +2026,7 @@ impl<'a> Codegen<'a> {
|
||||||
Some(self.ci.nodes.new_node_lit(ty, Kind::CInt { value: 0 }, [VOID]))
|
Some(self.ci.nodes.new_node_lit(ty, Kind::CInt { value: 0 }, [VOID]))
|
||||||
}
|
}
|
||||||
Expr::Idk { pos } => {
|
Expr::Idk { pos } => {
|
||||||
let Some(ty) = ctx.ty else {
|
inference!(ty, ctx, self, pos, "value", "@as(<ty>, idk)");
|
||||||
self.report(
|
|
||||||
pos,
|
|
||||||
"resulting value cannot be inferred from context, \
|
|
||||||
consider using `@as(<ty>, idk)` to hint the type",
|
|
||||||
);
|
|
||||||
return Value::NEVER;
|
|
||||||
};
|
|
||||||
|
|
||||||
if matches!(ty.expand(), ty::Kind::Struct(_) | ty::Kind::Slice(_)) {
|
if matches!(ty.expand(), ty::Kind::Struct(_) | ty::Kind::Slice(_)) {
|
||||||
let stck = self.ci.nodes.new_node(ty, Kind::Stck, [VOID, MEM]);
|
let stck = self.ci.nodes.new_node(ty, Kind::Stck, [VOID, MEM]);
|
||||||
|
@ -1756,7 +2036,7 @@ impl<'a> Codegen<'a> {
|
||||||
pos,
|
pos,
|
||||||
fa!(
|
fa!(
|
||||||
"type '{}' cannot be uninitialized, use a zero \
|
"type '{}' cannot be uninitialized, use a zero \
|
||||||
value instead ('@bitcast(0)' in case of pointers)",
|
value instead ('null' in case of pointers)",
|
||||||
self.ty_display(ty)
|
self.ty_display(ty)
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -2098,14 +2378,7 @@ impl<'a> Codegen<'a> {
|
||||||
let mut val = self.raw_expr(val)?;
|
let mut val = self.raw_expr(val)?;
|
||||||
self.strip_var(&mut val);
|
self.strip_var(&mut val);
|
||||||
|
|
||||||
let Some(ty) = ctx.ty else {
|
inference!(ty, ctx, self, pos, "type", "@as(<ty>, @bitcast(<expr>))");
|
||||||
self.report(
|
|
||||||
pos,
|
|
||||||
"resulting type cannot be inferred from context, \
|
|
||||||
consider using `@as(<ty>, @bitcast(<expr>))` to hint the type",
|
|
||||||
);
|
|
||||||
return Value::NEVER;
|
|
||||||
};
|
|
||||||
|
|
||||||
let (got, expected) = (self.tys.size_of(val.ty), self.tys.size_of(ty));
|
let (got, expected) = (self.tys.size_of(val.ty), self.tys.size_of(ty));
|
||||||
if got != expected {
|
if got != expected {
|
||||||
|
@ -2148,14 +2421,7 @@ impl<'a> Codegen<'a> {
|
||||||
return Value::NEVER;
|
return Value::NEVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(ty) = ctx.ty else {
|
inference!(ty, ctx, self, pos, "integer", "@as(<ty>, @intcast(<expr>))");
|
||||||
self.report(
|
|
||||||
pos,
|
|
||||||
"resulting integer cannot be inferred from context, \
|
|
||||||
consider using `@as(<int_ty>, @intcast(<expr>))` to hint the type",
|
|
||||||
);
|
|
||||||
return Value::NEVER;
|
|
||||||
};
|
|
||||||
|
|
||||||
if !ty.is_integer() {
|
if !ty.is_integer() {
|
||||||
self.report(
|
self.report(
|
||||||
|
@ -2183,14 +2449,7 @@ impl<'a> Codegen<'a> {
|
||||||
Some(val)
|
Some(val)
|
||||||
}
|
}
|
||||||
Expr::Directive { pos, name: "eca", args } => {
|
Expr::Directive { pos, name: "eca", args } => {
|
||||||
let Some(ty) = ctx.ty else {
|
inference!(ty, ctx, self, pos, "return type", "@as(<return_ty>, @eca(<expr>...))");
|
||||||
self.report(
|
|
||||||
pos,
|
|
||||||
"return type cannot be inferred from context, \
|
|
||||||
consider using `@as(<return_ty>, @eca(<expr>...))` to hint the type",
|
|
||||||
);
|
|
||||||
return Value::NEVER;
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut inps = Vc::from([NEVER]);
|
let mut inps = Vc::from([NEVER]);
|
||||||
let arg_base = self.tys.tmp.args.len();
|
let arg_base = self.tys.tmp.args.len();
|
||||||
|
@ -2447,14 +2706,8 @@ impl<'a> Codegen<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Expr::Tupl { pos, ty, fields, .. } => {
|
Expr::Tupl { pos, ty, fields, .. } => {
|
||||||
let Some(sty) = ty.map(|ty| self.ty(ty)).or(ctx.ty) else {
|
ctx.ty = ty.map(|ty| self.ty(ty)).or(ctx.ty);
|
||||||
self.report(
|
inference!(sty, ctx, self, pos, "struct or slice", "<struct_ty>.(...)");
|
||||||
pos,
|
|
||||||
"the type of struct cannot be inferred from context, \
|
|
||||||
use an explicit type instead: <type>.{ ... }",
|
|
||||||
);
|
|
||||||
return Value::NEVER;
|
|
||||||
};
|
|
||||||
|
|
||||||
match sty.expand() {
|
match sty.expand() {
|
||||||
ty::Kind::Struct(s) => {
|
ty::Kind::Struct(s) => {
|
||||||
|
@ -2544,14 +2797,7 @@ impl<'a> Codegen<'a> {
|
||||||
Some(self.ci.nodes.new_node_lit(ty::Id::TYPE, Kind::CInt { value }, [VOID]))
|
Some(self.ci.nodes.new_node_lit(ty::Id::TYPE, Kind::CInt { value }, [VOID]))
|
||||||
}
|
}
|
||||||
Expr::Ctor { pos, ty, fields, .. } => {
|
Expr::Ctor { pos, ty, fields, .. } => {
|
||||||
let Some(sty) = ty.map(|ty| self.ty(ty)).or(ctx.ty) else {
|
inference!(sty, ctx, self, pos, "struct", "<struct_ty>.{...}");
|
||||||
self.report(
|
|
||||||
pos,
|
|
||||||
"the type of struct cannot be inferred from context, \
|
|
||||||
use an explicit type instead: <type>.{ ... }",
|
|
||||||
);
|
|
||||||
return Value::NEVER;
|
|
||||||
};
|
|
||||||
|
|
||||||
let ty::Kind::Struct(s) = sty.expand() else {
|
let ty::Kind::Struct(s) = sty.expand() else {
|
||||||
let inferred = if ty.is_some() { "" } else { "inferred " };
|
let inferred = if ty.is_some() { "" } else { "inferred " };
|
||||||
|
@ -3136,7 +3382,7 @@ impl<'a> Codegen<'a> {
|
||||||
self.ci.finalize(&mut self.pool.nid_stack);
|
self.ci.finalize(&mut self.pool.nid_stack);
|
||||||
|
|
||||||
if self.errors.borrow().len() == prev_err_len {
|
if self.errors.borrow().len() == prev_err_len {
|
||||||
self.ci.emit_body(self.tys, self.files, sig, &mut self.pool.ralloc);
|
self.ci.emit_body(self.tys, self.files, sig, self.pool);
|
||||||
self.tys.ins.funcs[id as usize].code.append(&mut self.ci.code);
|
self.tys.ins.funcs[id as usize].code.append(&mut self.ci.code);
|
||||||
self.tys.ins.funcs[id as usize].relocs.append(&mut self.ci.relocs);
|
self.tys.ins.funcs[id as usize].relocs.append(&mut self.ci.relocs);
|
||||||
}
|
}
|
||||||
|
@ -3342,290 +3588,6 @@ impl TypeParser for Codegen<'_> {
|
||||||
|
|
||||||
// FIXME: make this more efficient (allocated with arena)
|
// FIXME: make this more efficient (allocated with arena)
|
||||||
|
|
||||||
fn loop_depth(target: Nid, nodes: &mut Nodes) -> LoopDepth {
|
|
||||||
if nodes[target].loop_depth != 0 {
|
|
||||||
return nodes[target].loop_depth;
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes[target].loop_depth = match nodes[target].kind {
|
|
||||||
Kind::Entry | Kind::Then | Kind::Else | Kind::Call { .. } | Kind::Return | Kind::If => {
|
|
||||||
let dpth = loop_depth(nodes[target].inputs[0], nodes);
|
|
||||||
if nodes[target].loop_depth != 0 {
|
|
||||||
return nodes[target].loop_depth;
|
|
||||||
}
|
|
||||||
dpth
|
|
||||||
}
|
|
||||||
Kind::Region => {
|
|
||||||
let l = loop_depth(nodes[target].inputs[0], nodes);
|
|
||||||
let r = loop_depth(nodes[target].inputs[1], nodes);
|
|
||||||
debug_assert_eq!(l, r);
|
|
||||||
l
|
|
||||||
}
|
|
||||||
Kind::Loop => {
|
|
||||||
let depth = loop_depth(nodes[target].inputs[0], nodes) + 1;
|
|
||||||
nodes[target].loop_depth = depth;
|
|
||||||
let mut cursor = nodes[target].inputs[1];
|
|
||||||
while cursor != target {
|
|
||||||
nodes[cursor].loop_depth = depth;
|
|
||||||
let next = if nodes[cursor].kind == Kind::Region {
|
|
||||||
loop_depth(nodes[cursor].inputs[0], nodes);
|
|
||||||
nodes[cursor].inputs[1]
|
|
||||||
} else {
|
|
||||||
idom(nodes, cursor)
|
|
||||||
};
|
|
||||||
debug_assert_ne!(next, VOID);
|
|
||||||
if matches!(nodes[cursor].kind, Kind::Then | Kind::Else) {
|
|
||||||
let other = *nodes[next]
|
|
||||||
.outputs
|
|
||||||
.iter()
|
|
||||||
.find(|&&n| nodes[n].kind != nodes[cursor].kind)
|
|
||||||
.unwrap();
|
|
||||||
if nodes[other].loop_depth == 0 {
|
|
||||||
nodes[other].loop_depth = depth - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cursor = next;
|
|
||||||
}
|
|
||||||
depth
|
|
||||||
}
|
|
||||||
Kind::Start | Kind::End => 1,
|
|
||||||
u => unreachable!("{u:?}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
nodes[target].loop_depth
|
|
||||||
}
|
|
||||||
|
|
||||||
fn idepth(nodes: &mut Nodes, target: Nid) -> IDomDepth {
|
|
||||||
if target == VOID {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if nodes[target].depth == 0 {
|
|
||||||
nodes[target].depth = match nodes[target].kind {
|
|
||||||
Kind::End | Kind::Start => unreachable!("{:?}", nodes[target].kind),
|
|
||||||
Kind::Region => {
|
|
||||||
idepth(nodes, nodes[target].inputs[0]).max(idepth(nodes, nodes[target].inputs[1]))
|
|
||||||
}
|
|
||||||
_ => idepth(nodes, nodes[target].inputs[0]),
|
|
||||||
} + 1;
|
|
||||||
}
|
|
||||||
nodes[target].depth
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fix_loops(nodes: &mut Nodes) {
|
|
||||||
'o: for l in nodes[LOOPS].outputs.clone() {
|
|
||||||
let mut cursor = nodes[l].inputs[1];
|
|
||||||
while cursor != l {
|
|
||||||
if nodes[cursor].kind == Kind::If
|
|
||||||
&& nodes[cursor]
|
|
||||||
.outputs
|
|
||||||
.clone()
|
|
||||||
.into_iter()
|
|
||||||
.any(|b| loop_depth(b, nodes) < loop_depth(cursor, nodes))
|
|
||||||
{
|
|
||||||
continue 'o;
|
|
||||||
}
|
|
||||||
cursor = idom(nodes, cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes[l].outputs.push(NEVER);
|
|
||||||
nodes[NEVER].inputs.push(l);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_up(nodes: &mut Nodes) {
|
|
||||||
fn collect_rpo(node: Nid, nodes: &mut Nodes, rpo: &mut Vec<Nid>) {
|
|
||||||
if !nodes.is_cfg(node) || !nodes.visited.set(node) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in 0..nodes[node].outputs.len() {
|
|
||||||
collect_rpo(nodes[node].outputs[i], nodes, rpo);
|
|
||||||
}
|
|
||||||
rpo.push(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_up_impl(node: Nid, nodes: &mut Nodes) {
|
|
||||||
if !nodes.visited.set(node) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in 1..nodes[node].inputs.len() {
|
|
||||||
let inp = nodes[node].inputs[i];
|
|
||||||
if !nodes[inp].kind.is_pinned() {
|
|
||||||
push_up_impl(inp, nodes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if nodes[node].kind.is_pinned() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut deepest = VOID;
|
|
||||||
for i in 1..nodes[node].inputs.len() {
|
|
||||||
let inp = nodes[node].inputs[i];
|
|
||||||
if idepth(nodes, inp) > idepth(nodes, deepest) {
|
|
||||||
deepest = idom(nodes, inp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if deepest == VOID {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let index = nodes[0].outputs.iter().position(|&p| p == node).unwrap();
|
|
||||||
nodes[0].outputs.remove(index);
|
|
||||||
nodes[node].inputs[0] = deepest;
|
|
||||||
debug_assert!(
|
|
||||||
!nodes[deepest].outputs.contains(&node)
|
|
||||||
|| matches!(nodes[deepest].kind, Kind::Call { .. }),
|
|
||||||
"{node} {:?} {deepest} {:?}",
|
|
||||||
nodes[node],
|
|
||||||
nodes[deepest]
|
|
||||||
);
|
|
||||||
nodes[deepest].outputs.push(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut rpo = vec![];
|
|
||||||
|
|
||||||
collect_rpo(VOID, nodes, &mut rpo);
|
|
||||||
|
|
||||||
for node in rpo.into_iter().rev() {
|
|
||||||
loop_depth(node, nodes);
|
|
||||||
for i in 0..nodes[node].inputs.len() {
|
|
||||||
push_up_impl(nodes[node].inputs[i], nodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
if matches!(nodes[node].kind, Kind::Loop | Kind::Region) {
|
|
||||||
for i in 0..nodes[node].outputs.len() {
|
|
||||||
let usage = nodes[node].outputs[i];
|
|
||||||
if nodes[usage].kind == Kind::Phi {
|
|
||||||
push_up_impl(usage, nodes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
debug_assert_eq!(
|
|
||||||
nodes
|
|
||||||
.iter()
|
|
||||||
.map(|(n, _)| n)
|
|
||||||
.filter(|&n| !nodes.visited.get(n)
|
|
||||||
&& !matches!(nodes[n].kind, Kind::Arg | Kind::Mem | Kind::Loops))
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
vec![],
|
|
||||||
"{:?}",
|
|
||||||
nodes
|
|
||||||
.iter()
|
|
||||||
.filter(|&(n, nod)| !nodes.visited.get(n)
|
|
||||||
&& !matches!(nod.kind, Kind::Arg | Kind::Mem | Kind::Loops))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_down(nodes: &mut Nodes, node: Nid) {
|
|
||||||
fn is_forward_edge(usage: Nid, def: Nid, nodes: &mut Nodes) -> bool {
|
|
||||||
match nodes[usage].kind {
|
|
||||||
Kind::Phi => {
|
|
||||||
nodes[usage].inputs[2] != def || nodes[nodes[usage].inputs[0]].kind != Kind::Loop
|
|
||||||
}
|
|
||||||
Kind::Loop => nodes[usage].inputs[1] != def,
|
|
||||||
_ => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn better(nodes: &mut Nodes, is: Nid, then: Nid) -> bool {
|
|
||||||
debug_assert_ne!(idepth(nodes, is), idepth(nodes, then), "{is} {then}");
|
|
||||||
loop_depth(is, nodes) < loop_depth(then, nodes)
|
|
||||||
|| idepth(nodes, is) > idepth(nodes, then)
|
|
||||||
|| nodes[then].kind == Kind::If
|
|
||||||
}
|
|
||||||
|
|
||||||
if !nodes.visited.set(node) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for usage in nodes[node].outputs.clone() {
|
|
||||||
if is_forward_edge(usage, node, nodes) && nodes[node].kind == Kind::Stre {
|
|
||||||
push_down(nodes, usage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for usage in nodes[node].outputs.clone() {
|
|
||||||
if is_forward_edge(usage, node, nodes) {
|
|
||||||
push_down(nodes, usage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if nodes[node].kind.is_pinned() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut min = None::<Nid>;
|
|
||||||
for i in 0..nodes[node].outputs.len() {
|
|
||||||
let usage = nodes[node].outputs[i];
|
|
||||||
let ub = use_block(node, usage, nodes);
|
|
||||||
min = min.map(|m| common_dom(ub, m, nodes)).or(Some(ub));
|
|
||||||
}
|
|
||||||
let mut min = min.unwrap();
|
|
||||||
|
|
||||||
debug_assert!(nodes.dominates(nodes[node].inputs[0], min));
|
|
||||||
|
|
||||||
let mut cursor = min;
|
|
||||||
while cursor != nodes[node].inputs[0] {
|
|
||||||
cursor = idom(nodes, cursor);
|
|
||||||
if better(nodes, cursor, min) {
|
|
||||||
min = cursor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if nodes[min].kind.ends_basic_block() {
|
|
||||||
min = idom(nodes, min);
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes.check_dominance(node, min, true);
|
|
||||||
|
|
||||||
let prev = nodes[node].inputs[0];
|
|
||||||
debug_assert!(idepth(nodes, min) >= idepth(nodes, prev));
|
|
||||||
let index = nodes[prev].outputs.iter().position(|&p| p == node).unwrap();
|
|
||||||
nodes[prev].outputs.remove(index);
|
|
||||||
nodes[node].inputs[0] = min;
|
|
||||||
nodes[min].outputs.push(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn use_block(target: Nid, from: Nid, nodes: &mut Nodes) -> Nid {
|
|
||||||
if nodes[from].kind != Kind::Phi {
|
|
||||||
return idom(nodes, from);
|
|
||||||
}
|
|
||||||
|
|
||||||
let index = nodes[from].inputs.iter().position(|&n| n == target).unwrap();
|
|
||||||
nodes[nodes[from].inputs[0]].inputs[index - 1]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn idom(nodes: &mut Nodes, target: Nid) -> Nid {
|
|
||||||
match nodes[target].kind {
|
|
||||||
Kind::Start => VOID,
|
|
||||||
Kind::End => unreachable!(),
|
|
||||||
Kind::Region => {
|
|
||||||
let &[lcfg, rcfg] = nodes[target].inputs.as_slice() else { unreachable!() };
|
|
||||||
common_dom(lcfg, rcfg, nodes)
|
|
||||||
}
|
|
||||||
_ => nodes[target].inputs[0],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn common_dom(mut a: Nid, mut b: Nid, nodes: &mut Nodes) -> Nid {
|
|
||||||
while a != b {
|
|
||||||
let [ldepth, rdepth] = [idepth(nodes, a), idepth(nodes, b)];
|
|
||||||
if ldepth >= rdepth {
|
|
||||||
a = idom(nodes, a);
|
|
||||||
}
|
|
||||||
if ldepth <= rdepth {
|
|
||||||
b = idom(nodes, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
a
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use {
|
use {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use {
|
use {
|
||||||
super::{ItemCtx, Nid, Nodes, RallocBRef, Regalloc, ARG_START, NEVER, VOID},
|
super::{ItemCtx, Nid, Nodes, Pool, RallocBRef, Regalloc, ARG_START, NEVER, VOID},
|
||||||
crate::{
|
crate::{
|
||||||
lexer::TokenKind,
|
lexer::TokenKind,
|
||||||
parser, reg,
|
parser, reg,
|
||||||
|
@ -475,23 +475,17 @@ impl ItemCtx {
|
||||||
tys: &mut Types,
|
tys: &mut Types,
|
||||||
files: &[parser::Ast],
|
files: &[parser::Ast],
|
||||||
sig: Sig,
|
sig: Sig,
|
||||||
ralloc: &mut Regalloc,
|
pool: &mut Pool,
|
||||||
) {
|
) {
|
||||||
self.emit_body(tys, files, sig, ralloc);
|
self.emit_body(tys, files, sig, pool);
|
||||||
self.code.truncate(self.code.len() - instrs::jala(0, 0, 0).0);
|
self.code.truncate(self.code.len() - instrs::jala(0, 0, 0).0);
|
||||||
self.emit(instrs::tx());
|
self.emit(instrs::tx());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn emit_body(
|
pub fn emit_body(&mut self, tys: &mut Types, files: &[parser::Ast], sig: Sig, pool: &mut Pool) {
|
||||||
&mut self,
|
|
||||||
tys: &mut Types,
|
|
||||||
files: &[parser::Ast],
|
|
||||||
sig: Sig,
|
|
||||||
ralloc: &mut Regalloc,
|
|
||||||
) {
|
|
||||||
self.nodes.check_final_integrity(tys, files);
|
self.nodes.check_final_integrity(tys, files);
|
||||||
self.nodes.graphviz(tys, files);
|
self.nodes.graphviz(tys, files);
|
||||||
self.nodes.gcm();
|
self.nodes.gcm(&mut pool.nid_stack);
|
||||||
self.nodes.basic_blocks();
|
self.nodes.basic_blocks();
|
||||||
self.nodes.graphviz(tys, files);
|
self.nodes.graphviz(tys, files);
|
||||||
|
|
||||||
|
@ -526,7 +520,7 @@ impl ItemCtx {
|
||||||
self.nodes[MEM].outputs = mems;
|
self.nodes[MEM].outputs = mems;
|
||||||
}
|
}
|
||||||
|
|
||||||
let saved = self.emit_body_code(sig, tys, files, ralloc);
|
let saved = self.emit_body_code(sig, tys, files, &mut pool.ralloc);
|
||||||
|
|
||||||
if let Some(last_ret) = self.ret_relocs.last()
|
if let Some(last_ret) = self.ret_relocs.last()
|
||||||
&& last_ret.offset as usize == self.code.len() - 5
|
&& last_ret.offset as usize == self.code.len() - 5
|
||||||
|
|
Loading…
Reference in a new issue