improving load analisys

This commit is contained in:
Jakub Doka 2024-11-10 17:32:24 +01:00
parent 8b98c2ed1b
commit 1e02efc1eb
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
3 changed files with 279 additions and 144 deletions

View file

@ -612,6 +612,28 @@ main := fn(): uint {
### Purely Testing Examples ### Purely Testing Examples
#### storing_into_nullable_struct
```hb
Struct := struct {inner: uint}
optional := fn(): ?Struct {
return .(10)
}
do_stuff := fn(arg: Struct): uint {
return arg.inner
}
main := fn(): void {
val := optional()
if val == null {
return
}
val.inner = 100
inner := do_stuff(val)
}
```
#### scheduling_block_did_dirty #### scheduling_block_did_dirty
```hb ```hb
Struct := struct { Struct := struct {

View file

@ -23,7 +23,7 @@ use {
cell::{Cell, RefCell}, cell::{Cell, RefCell},
fmt::{self, Debug, Display, Write}, fmt::{self, Debug, Display, Write},
format_args as fa, mem, format_args as fa, mem,
ops::{self}, ops::{self, Range},
}, },
hashbrown::hash_map, hashbrown::hash_map,
hbbytecode::DisasmError, hbbytecode::DisasmError,
@ -484,6 +484,7 @@ impl Nodes {
ctrl: &StrongRef, ctrl: &StrongRef,
to: &mut Scope, to: &mut Scope,
from: &mut Scope, from: &mut Scope,
tys: &Types,
) { ) {
for (i, (to_value, from_value)) in to.vars.iter_mut().zip(from.vars.iter_mut()).enumerate() for (i, (to_value, from_value)) in to.vars.iter_mut().zip(from.vars.iter_mut()).enumerate()
{ {
@ -495,7 +496,8 @@ impl Nodes {
debug_assert!(!to_value.ptr); debug_assert!(!to_value.ptr);
debug_assert!(!from_value.ptr); debug_assert!(!from_value.ptr);
let inps = [ctrl.get(), from_value.value(), to_value.value()]; let inps = [ctrl.get(), from_value.value(), to_value.value()];
to_value.set_value_remove(self.new_node(from_value.ty, Kind::Phi, inps), self); to_value
.set_value_remove(self.new_node(from_value.ty, Kind::Phi, inps, tys), self);
} }
} }
} }
@ -510,7 +512,7 @@ impl Nodes {
let inps = [ctrl.get(), from_class.last_store.get(), to_class.last_store.get()]; let inps = [ctrl.get(), from_class.last_store.get(), to_class.last_store.get()];
to_class to_class
.last_store .last_store
.set_remove(self.new_node(ty::Id::VOID, Kind::Phi, inps), self); .set_remove(self.new_node(ty::Id::VOID, Kind::Phi, inps, tys), self);
} }
} }
} }
@ -667,9 +669,9 @@ impl Nodes {
} }
} }
fn new_node(&mut self, ty: ty::Id, kind: Kind, inps: impl Into<Vc>) -> Nid { fn new_node(&mut self, ty: ty::Id, kind: Kind, inps: impl Into<Vc>, tys: &Types) -> Nid {
let id = self.new_node_nop(ty, kind, inps); let id = self.new_node_nop(ty, kind, inps);
if let Some(opt) = self.peephole(id) { if let Some(opt) = self.peephole(id, tys) {
debug_assert_ne!(opt, id); debug_assert_ne!(opt, id);
self.lock(opt); self.lock(opt);
self.remove(id); self.remove(id);
@ -685,11 +687,11 @@ impl Nodes {
} }
fn new_const_lit(&mut self, ty: ty::Id, value: impl Into<i64>) -> Value { fn new_const_lit(&mut self, ty: ty::Id, value: impl Into<i64>) -> Value {
self.new_node_lit(ty, Kind::CInt { value: value.into() }, [VOID]) Value::new(self.new_const(ty, value)).ty(ty)
} }
fn new_node_lit(&mut self, ty: ty::Id, kind: Kind, inps: impl Into<Vc>) -> Value { fn new_node_lit(&mut self, ty: ty::Id, kind: Kind, inps: impl Into<Vc>, tys: &Types) -> Value {
Value::new(self.new_node(ty, kind, inps)).ty(ty) Value::new(self.new_node(ty, kind, inps, tys)).ty(ty)
} }
fn lock(&mut self, target: Nid) { fn lock(&mut self, target: Nid) {
@ -727,15 +729,15 @@ impl Nodes {
true true
} }
fn late_peephole(&mut self, target: Nid) -> Option<Nid> { fn late_peephole(&mut self, target: Nid, tys: &Types) -> Option<Nid> {
if let Some(id) = self.peephole(target) { if let Some(id) = self.peephole(target, tys) {
self.replace(target, id); self.replace(target, id);
return None; return None;
} }
None None
} }
fn iter_peeps(&mut self, mut fuel: usize, stack: &mut Vec<Nid>) { fn iter_peeps(&mut self, mut fuel: usize, stack: &mut Vec<Nid>, tys: &Types) {
debug_assert!(stack.is_empty()); debug_assert!(stack.is_empty());
self.iter() self.iter()
@ -756,7 +758,7 @@ impl Nodes {
continue; continue;
} }
if let Some(new) = self.peephole(node) { if let Some(new) = self.peephole(node, tys) {
self.replace(node, new); self.replace(node, new);
self.push_adjacent_nodes(new, stack); self.push_adjacent_nodes(new, stack);
} }
@ -806,7 +808,7 @@ impl Nodes {
} }
} }
fn peephole(&mut self, target: Nid) -> Option<Nid> { fn peephole(&mut self, target: Nid, tys: &Types) -> Option<Nid> {
use {Kind as K, TokenKind as T}; use {Kind as K, TokenKind as T};
match self[target].kind { match self[target].kind {
K::BinOp { op } => { K::BinOp { op } => {
@ -828,9 +830,12 @@ impl Nodes {
T::Sub => return Some(self.new_const(ty, 0)), T::Sub => return Some(self.new_const(ty, 0)),
T::Add => { T::Add => {
let rhs = self.new_const(ty, 2); let rhs = self.new_const(ty, 2);
return Some( return Some(self.new_node(
self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, lhs, rhs]), ty,
); K::BinOp { op: T::Mul },
[ctrl, lhs, rhs],
tys,
));
} }
_ => {} _ => {}
} }
@ -864,13 +869,13 @@ impl Nodes {
{ {
// (a op #b) op #c => a op (#b op #c) // (a op #b) op #c => a op (#b op #c)
let new_rhs = self.new_const(ty, op.apply_binop(av, bv, is_float)); let new_rhs = self.new_const(ty, op.apply_binop(av, bv, is_float));
return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs])); return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs], tys));
} }
if self.is_const(b) { if self.is_const(b) {
// (a op #b) op c => (a op c) op #b // (a op #b) op c => (a op c) op #b
let new_lhs = self.new_node(ty, K::BinOp { op }, [ctrl, a, rhs]); let new_lhs = self.new_node(ty, K::BinOp { op }, [ctrl, a, rhs], tys);
return Some(self.new_node(ty, K::BinOp { op }, [ctrl, new_lhs, b])); return Some(self.new_node(ty, K::BinOp { op }, [ctrl, new_lhs, b], tys));
} }
} }
@ -881,7 +886,12 @@ impl Nodes {
{ {
// a * #n + a => a * (#n + 1) // a * #n + a => a * (#n + 1)
let new_rhs = self.new_const(ty, value + 1); let new_rhs = self.new_const(ty, value + 1);
return Some(self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, rhs, new_rhs])); return Some(self.new_node(
ty,
K::BinOp { op: T::Mul },
[ctrl, rhs, new_rhs],
tys,
));
} }
if op == T::Sub if op == T::Sub
@ -890,23 +900,24 @@ impl Nodes {
&& let K::CInt { value: b } = self[self[lhs].inputs[2]].kind && let K::CInt { value: b } = self[self[lhs].inputs[2]].kind
{ {
let new_rhs = self.new_const(ty, b - a); let new_rhs = self.new_const(ty, b - a);
return Some(self.new_node(ty, K::BinOp { op: T::Add }, [ return Some(self.new_node(
ctrl, ty,
self[lhs].inputs[1], K::BinOp { op: T::Add },
new_rhs, [ctrl, self[lhs].inputs[1], new_rhs],
])); tys,
));
} }
if op == T::Sub && self[lhs].kind == (K::BinOp { op }) { if op == T::Sub && self[lhs].kind == (K::BinOp { op }) {
// (a - b) - c => a - (b + c) // (a - b) - c => a - (b + c)
let &[_, a, b] = self[lhs].inputs.as_slice() else { unreachable!() }; let &[_, a, b] = self[lhs].inputs.as_slice() else { unreachable!() };
let c = rhs; let c = rhs;
let new_rhs = self.new_node(ty, K::BinOp { op: T::Add }, [ctrl, b, c]); let new_rhs = self.new_node(ty, K::BinOp { op: T::Add }, [ctrl, b, c], tys);
return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs])); return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs], tys));
} }
if changed { if changed {
return Some(self.new_node(ty, self[target].kind, [ctrl, lhs, rhs])); return Some(self.new_node(ty, self[target].kind, [ctrl, lhs, rhs], tys));
} }
} }
K::UnOp { op } => { K::UnOp { op } => {
@ -1043,11 +1054,12 @@ impl Nodes {
&& self[lhs].inputs[2] == self[rhs].inputs[2] && self[lhs].inputs[2] == self[rhs].inputs[2]
&& self[lhs].inputs[3] == self[rhs].inputs[3] && self[lhs].inputs[3] == self[rhs].inputs[3]
{ {
let pick_value = self.new_node(self[lhs].ty, Kind::Phi, [ let pick_value = self.new_node(
ctrl, self[lhs].ty,
self[lhs].inputs[1], Kind::Phi,
self[rhs].inputs[1], [ctrl, self[lhs].inputs[1], self[rhs].inputs[1]],
]); tys,
);
let mut vc = Vc::from([VOID, pick_value, self[lhs].inputs[2]]); let mut vc = Vc::from([VOID, pick_value, self[lhs].inputs[2]]);
for &rest in &self[lhs].inputs[3..] { for &rest in &self[lhs].inputs[3..] {
vc.push(rest); vc.push(rest);
@ -1055,7 +1067,7 @@ impl Nodes {
for &rest in &self[rhs].inputs[4..] { for &rest in &self[rhs].inputs[4..] {
vc.push(rest); vc.push(rest);
} }
return Some(self.new_node(self[lhs].ty, Kind::Stre, vc)); return Some(self.new_node(self[lhs].ty, Kind::Stre, vc, tys));
} }
} }
K::Stck => { K::Stck => {
@ -1183,11 +1195,14 @@ impl Nodes {
if let Kind::BinOp { op } = self[oper].kind { if let Kind::BinOp { op } = self[oper].kind {
debug_assert_eq!(self[oper].outputs.len(), 1); debug_assert_eq!(self[oper].outputs.len(), 1);
debug_assert_eq!(self[self[oper].outputs[0]].kind, Kind::Stre); debug_assert_eq!(self[self[oper].outputs[0]].kind, Kind::Stre);
region = self.new_node(self[oper].ty, Kind::BinOp { op }, [ let new_region = self.new_node(
VOID, self[oper].ty,
region, Kind::BinOp { op },
self[oper].inputs[2], [VOID, region, self[oper].inputs[2]],
]); tys,
);
self.pass_aclass(self.aclass_index(region).1, new_region);
region = new_region;
oper = self[oper].outputs[0]; oper = self[oper].outputs[0];
} }
@ -1195,7 +1210,7 @@ impl Nodes {
debug_assert_eq!(inps.len(), 4); debug_assert_eq!(inps.len(), 4);
inps[2] = region; inps[2] = region;
inps[3] = prev_store; inps[3] = prev_store;
prev_store = self.new_node(self[oper].ty, Kind::Stre, inps); prev_store = self.new_node(self[oper].ty, Kind::Stre, inps, tys);
} }
return Some(prev_store); return Some(prev_store);
@ -1220,35 +1235,62 @@ impl Nodes {
} }
} }
K::Load => { K::Load => {
let &[_, region, store] = self[target].inputs.as_slice() else { unreachable!() }; fn range_of(s: &Nodes, mut region: Nid, ty: ty::Id, tys: &Types) -> Range<usize> {
let loc = s.aclass_index(region).1;
if self[store].kind == Kind::Stre let full_size = tys.size_of(
&& self[store].inputs[2] == region if matches!(s[loc].kind, Kind::Stck | Kind::Arg | Kind::Global { .. }) {
&& self[store].ty == self[target].ty s[loc].ty
&& self[store] } else if let Some(ptr) = tys.base_of(s[loc].ty) {
.outputs ptr
.iter() } else {
.all(|&n| !matches!(self[n].kind, Kind::Call { .. })) return 0..usize::MAX;
},
);
let size = tys.size_of(ty);
loop {
break match s[region].kind {
_ if region == loc => 0..size as usize,
Kind::Assert { kind: AssertKind::NullCheck, .. } => {
region = s[region].inputs[2];
continue;
}
Kind::BinOp { op: TokenKind::Add | TokenKind::Sub }
if let Kind::CInt { value } = s[s[region].inputs[2]].kind
&& s[region].inputs[1] == loc =>
{ {
return Some(self[store].inputs[1]); value as usize..value as usize + size as usize
}
_ => 0..full_size as usize,
};
}
} }
let (index, reg) = self.aclass_index(region); let &[ctrl, region, store] = self[target].inputs.as_slice() else { unreachable!() };
if index != 0 && self[reg].kind == Kind::Stck { let load_range = range_of(self, region, self[target].ty, tys);
let mut cursor = store; let mut cursor = store;
while cursor != MEM
&& self[cursor].kind == Kind::Stre while cursor != MEM && self[cursor].kind != Kind::Phi {
&& self[cursor].inputs[1] != VOID if self[cursor].inputs[0] == ctrl
&& self[cursor] && self[cursor].inputs[2] == region
.outputs && self[cursor].ty == self[target].ty
.iter()
.all(|&n| !matches!(self[n].kind, Kind::Call { .. }))
{ {
if self[cursor].inputs[2] == region && self[cursor].ty == self[target].ty {
return Some(self[cursor].inputs[1]); return Some(self[cursor].inputs[1]);
} }
let range = range_of(self, self[cursor].inputs[2], self[cursor].ty, tys);
if range.start >= load_range.end || range.end <= load_range.start {
cursor = self[cursor].inputs[3]; cursor = self[cursor].inputs[3];
continue;
} }
break;
}
if store != cursor {
return Some(self.new_node(
self[target].ty,
Kind::Load,
[ctrl, region, cursor],
tys,
));
} }
} }
K::Loop => { K::Loop => {
@ -2078,29 +2120,31 @@ impl ItemCtx {
self.nodes.clear(); self.nodes.clear();
self.scope.vars.clear(); self.scope.vars.clear();
let start = self.nodes.new_node(ty::Id::VOID, Kind::Start, []); let start = self.nodes.new_node_nop(ty::Id::VOID, Kind::Start, []);
debug_assert_eq!(start, VOID); debug_assert_eq!(start, VOID);
let end = self.nodes.new_node(ty::Id::NEVER, Kind::End, []); let end = self.nodes.new_node_nop(ty::Id::NEVER, Kind::End, []);
debug_assert_eq!(end, NEVER); debug_assert_eq!(end, NEVER);
self.nodes.lock(end); self.nodes.lock(end);
self.ctrl = self.ctrl = StrongRef::new(
StrongRef::new(self.nodes.new_node(ty::Id::VOID, Kind::Entry, [VOID]), &mut self.nodes); self.nodes.new_node_nop(ty::Id::VOID, Kind::Entry, [VOID]),
&mut self.nodes,
);
debug_assert_eq!(self.ctrl.get(), ENTRY); debug_assert_eq!(self.ctrl.get(), ENTRY);
let mem = self.nodes.new_node(ty::Id::VOID, Kind::Mem, [VOID]); let mem = self.nodes.new_node_nop(ty::Id::VOID, Kind::Mem, [VOID]);
debug_assert_eq!(mem, MEM); debug_assert_eq!(mem, MEM);
self.nodes.lock(mem); self.nodes.lock(mem);
let loops = self.nodes.new_node(ty::Id::VOID, Kind::Loops, [VOID]); let loops = self.nodes.new_node_nop(ty::Id::VOID, Kind::Loops, [VOID]);
debug_assert_eq!(loops, LOOPS); debug_assert_eq!(loops, LOOPS);
self.nodes.lock(loops); self.nodes.lock(loops);
self.scope.aclasses.push(AClass::new(&mut self.nodes)); // DEFAULT self.scope.aclasses.push(AClass::new(&mut self.nodes)); // DEFAULT
self.scope.aclasses.push(AClass::new(&mut self.nodes)); // GLOBAL self.scope.aclasses.push(AClass::new(&mut self.nodes)); // GLOBAL
} }
fn finalize(&mut self, stack: &mut Vec<Nid>, _tys: &Types, _files: &[parser::Ast]) { fn finalize(&mut self, stack: &mut Vec<Nid>, tys: &Types, _files: &[parser::Ast]) {
self.scope.clear(&mut self.nodes); self.scope.clear(&mut self.nodes);
mem::take(&mut self.ctrl).soft_remove(&mut self.nodes); mem::take(&mut self.ctrl).soft_remove(&mut self.nodes);
self.nodes.iter_peeps(1000, stack); self.nodes.iter_peeps(1000, stack, tys);
} }
fn unlock(&mut self) { fn unlock(&mut self) {
@ -2421,7 +2465,7 @@ impl<'a> Codegen<'a> {
self.ci.nodes.load_loop_aclass(index, aclass, &mut self.ci.loops); self.ci.nodes.load_loop_aclass(index, aclass, &mut self.ci.loops);
let vc = Vc::from([aclass.clobber.get(), value, region, aclass.last_store.get()]); let vc = Vc::from([aclass.clobber.get(), value, region, aclass.last_store.get()]);
mem::take(&mut aclass.last_store).soft_remove(&mut self.ci.nodes); mem::take(&mut aclass.last_store).soft_remove(&mut self.ci.nodes);
let store = self.ci.nodes.new_node(ty, Kind::Stre, vc); let store = self.ci.nodes.new_node(ty, Kind::Stre, vc, self.tys);
aclass.last_store = StrongRef::new(store, &mut self.ci.nodes); aclass.last_store = StrongRef::new(store, &mut self.ci.nodes);
store store
} }
@ -2446,7 +2490,7 @@ impl<'a> Codegen<'a> {
let aclass = &mut self.ci.scope.aclasses[index]; let aclass = &mut self.ci.scope.aclasses[index];
self.ci.nodes.load_loop_aclass(index, aclass, &mut self.ci.loops); self.ci.nodes.load_loop_aclass(index, aclass, &mut self.ci.loops);
let vc = [aclass.clobber.get(), region, aclass.last_store.get()]; let vc = [aclass.clobber.get(), region, aclass.last_store.get()];
self.ci.nodes.new_node(ty, Kind::Load, vc) self.ci.nodes.new_node(ty, Kind::Load, vc, self.tys)
} }
fn make_func_reachable(&mut self, func: ty::Func) { fn make_func_reachable(&mut self, func: ty::Func) {
@ -2576,7 +2620,7 @@ impl<'a> Codegen<'a> {
.0 .0
} }
}; };
let global = self.ci.nodes.new_node(ty, Kind::Global { global }, [VOID]); let global = self.ci.nodes.new_node_nop(ty, Kind::Global { global }, [VOID]);
self.ci.nodes[global].aclass = GLOBAL_ACLASS as _; self.ci.nodes[global].aclass = GLOBAL_ACLASS as _;
Some(Value::new(global).ty(ty)) Some(Value::new(global).ty(ty))
} }
@ -2608,15 +2652,28 @@ impl<'a> Codegen<'a> {
self.ci.nodes.bind(ret, NEVER); self.ci.nodes.bind(ret, NEVER);
} else if let Some((pv, ctrl, scope)) = &mut self.ci.inline_ret { } else if let Some((pv, ctrl, scope)) = &mut self.ci.inline_ret {
ctrl.set( ctrl.set(
self.ci self.ci.nodes.new_node(
.nodes ty::Id::VOID,
.new_node(ty::Id::VOID, Kind::Region, [self.ci.ctrl.get(), ctrl.get()]), Kind::Region,
[self.ci.ctrl.get(), ctrl.get()],
self.tys,
),
&mut self.ci.nodes, &mut self.ci.nodes,
); );
self.ci.nodes.merge_scopes(&mut self.ci.loops, ctrl, scope, &mut self.ci.scope); self.ci.nodes.merge_scopes(
&mut self.ci.loops,
ctrl,
scope,
&mut self.ci.scope,
self.tys,
);
self.ci.nodes.unlock(pv.id); self.ci.nodes.unlock(pv.id);
pv.id = pv.id = self.ci.nodes.new_node(
self.ci.nodes.new_node(value.ty, Kind::Phi, [ctrl.get(), value.id, pv.id]); value.ty,
Kind::Phi,
[ctrl.get(), value.id, pv.id],
self.tys,
);
self.ci.nodes.lock(pv.id); self.ci.nodes.lock(pv.id);
self.ci.ctrl.set(NEVER, &mut self.ci.nodes); self.ci.ctrl.set(NEVER, &mut self.ci.nodes);
} else { } else {
@ -2741,12 +2798,20 @@ impl<'a> Codegen<'a> {
let val = let val =
self.expr_ctx(val, Ctx::default().with_ty(ctx.ty.unwrap_or(ty::Id::INT)))?; self.expr_ctx(val, Ctx::default().with_ty(ctx.ty.unwrap_or(ty::Id::INT)))?;
if val.ty.is_integer() { if val.ty.is_integer() {
Some(self.ci.nodes.new_node_lit(val.ty, Kind::UnOp { op }, [VOID, val.id])) Some(self.ci.nodes.new_node_lit(
val.ty,
Kind::UnOp { op },
[VOID, val.id],
self.tys,
))
} else if val.ty.is_float() { } else if val.ty.is_float() {
let value = self.ci.nodes.new_const(val.ty, (-1f64).to_bits() as i64); let value = self.ci.nodes.new_const(val.ty, (-1f64).to_bits() as i64);
Some(self.ci.nodes.new_node_lit(val.ty, Kind::BinOp { op: TokenKind::Mul }, [ Some(self.ci.nodes.new_node_lit(
VOID, val.id, value, val.ty,
])) Kind::BinOp { op: TokenKind::Mul },
[VOID, val.id, value],
self.tys,
))
} else { } else {
self.report(pos, fa!("cant negate '{}'", self.ty_display(val.ty))); self.report(pos, fa!("cant negate '{}'", self.ty_display(val.ty)));
Value::NEVER Value::NEVER
@ -2837,8 +2902,12 @@ impl<'a> Codegen<'a> {
self.implicit_unwrap(right.pos(), &mut rhs); self.implicit_unwrap(right.pos(), &mut rhs);
let (ty, aclass) = self.binop_ty(pos, &mut lhs, &mut rhs, op); let (ty, aclass) = self.binop_ty(pos, &mut lhs, &mut rhs, op);
let inps = [VOID, lhs.id, rhs.id]; let inps = [VOID, lhs.id, rhs.id];
let bop = let bop = self.ci.nodes.new_node_lit(
self.ci.nodes.new_node_lit(ty.bin_ret(op), Kind::BinOp { op }, inps); ty.bin_ret(op),
Kind::BinOp { op },
inps,
self.tys,
);
self.ci.nodes.pass_aclass(aclass, bop.id); self.ci.nodes.pass_aclass(aclass, bop.id);
Some(bop) Some(bop)
} }
@ -2887,19 +2956,28 @@ impl<'a> Codegen<'a> {
self.assert_ty(index.pos(), &mut idx, ty::Id::DEFAULT_INT, "subscript"); self.assert_ty(index.pos(), &mut idx, ty::Id::DEFAULT_INT, "subscript");
let size = self.ci.nodes.new_const(ty::Id::INT, self.tys.size_of(elem)); let size = self.ci.nodes.new_const(ty::Id::INT, self.tys.size_of(elem));
let inps = [VOID, idx.id, size]; let inps = [VOID, idx.id, size];
let offset = let offset = self.ci.nodes.new_node(
self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Mul }, inps); ty::Id::INT,
Kind::BinOp { op: TokenKind::Mul },
inps,
self.tys,
);
let aclass = self.ci.nodes.aclass_index(bs.id).1; let aclass = self.ci.nodes.aclass_index(bs.id).1;
let inps = [VOID, bs.id, offset]; let inps = [VOID, bs.id, offset];
let ptr = let ptr = self.ci.nodes.new_node(
self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Add }, inps); ty::Id::INT,
Kind::BinOp { op: TokenKind::Add },
inps,
self.tys,
);
self.ci.nodes.pass_aclass(aclass, ptr); self.ci.nodes.pass_aclass(aclass, ptr);
Some(Value::ptr(ptr).ty(elem)) Some(Value::ptr(ptr).ty(elem))
} }
Expr::Embed { id, .. } => { Expr::Embed { id, .. } => {
let glob = &self.tys.ins.globals[id]; let glob = &self.tys.ins.globals[id];
let g = self.ci.nodes.new_node(glob.ty, Kind::Global { global: id }, [VOID]); let g =
self.ci.nodes.new_node(glob.ty, Kind::Global { global: id }, [VOID], self.tys);
Some(Value::ptr(g).ty(glob.ty)) Some(Value::ptr(g).ty(glob.ty))
} }
Expr::Directive { name: "sizeof", args: [ty], .. } => { Expr::Directive { name: "sizeof", args: [ty], .. } => {
@ -3037,11 +3115,12 @@ impl<'a> Codegen<'a> {
} }
if self.tys.size_of(val.ty) != self.tys.size_of(ty) { if self.tys.size_of(val.ty) != self.tys.size_of(ty) {
Some( Some(self.ci.nodes.new_node_lit(
self.ci ty,
.nodes Kind::UnOp { op: TokenKind::Float },
.new_node_lit(ty, Kind::UnOp { op: TokenKind::Float }, [VOID, val.id]), [VOID, val.id],
) self.tys,
))
} else { } else {
Some(val.ty(ty)) Some(val.ty(ty))
} }
@ -3060,11 +3139,12 @@ impl<'a> Codegen<'a> {
} }
}; };
Some( Some(self.ci.nodes.new_node_lit(
self.ci ret_ty,
.nodes Kind::UnOp { op: TokenKind::Number },
.new_node_lit(ret_ty, Kind::UnOp { op: TokenKind::Number }, [VOID, val.id]), [VOID, val.id],
) self.tys,
))
} }
Expr::Directive { name: "itf", args: [expr], .. } => { Expr::Directive { name: "itf", args: [expr], .. } => {
let mut val = self.expr(expr)?; let mut val = self.expr(expr)?;
@ -3076,11 +3156,12 @@ impl<'a> Codegen<'a> {
self.assert_ty(expr.pos(), &mut val, expected, "converted integer"); self.assert_ty(expr.pos(), &mut val, expected, "converted integer");
Some( Some(self.ci.nodes.new_node_lit(
self.ci ret_ty,
.nodes Kind::UnOp { op: TokenKind::Float },
.new_node_lit(ret_ty, Kind::UnOp { op: TokenKind::Float }, [VOID, val.id]), [VOID, val.id],
) self.tys,
))
} }
Expr::Directive { name: "as", args: [ty, expr], .. } => { Expr::Directive { name: "as", args: [ty, expr], .. } => {
let ty = self.ty(ty); let ty = self.ty(ty);
@ -3124,7 +3205,7 @@ impl<'a> Codegen<'a> {
inps[0] = self.ci.ctrl.get(); inps[0] = self.ci.ctrl.get();
self.ci.ctrl.set( self.ci.ctrl.set(
self.ci.nodes.new_node(ty, Kind::Call { func: ty::Func::ECA, args }, inps), self.ci.nodes.new_node_nop(ty, Kind::Call { func: ty::Func::ECA, args }, inps),
&mut self.ci.nodes, &mut self.ci.nodes,
); );
@ -3202,7 +3283,11 @@ impl<'a> Codegen<'a> {
inps[0] = self.ci.ctrl.get(); inps[0] = self.ci.ctrl.get();
self.ci.ctrl.set( self.ci.ctrl.set(
self.ci.nodes.new_node(sig.ret, Kind::Call { func: fu, args: sig.args }, inps), self.ci.nodes.new_node_nop(
sig.ret,
Kind::Call { func: fu, args: sig.args },
inps,
),
&mut self.ci.nodes, &mut self.ci.nodes,
); );
@ -3517,11 +3602,12 @@ impl<'a> Codegen<'a> {
} }
Expr::Loop { body, .. } => { Expr::Loop { body, .. } => {
self.ci.ctrl.set( self.ci.ctrl.set(
self.ci.nodes.new_node(ty::Id::VOID, Kind::Loop, [ self.ci.nodes.new_node(
self.ci.ctrl.get(), ty::Id::VOID,
self.ci.ctrl.get(), Kind::Loop,
LOOPS, [self.ci.ctrl.get(), self.ci.ctrl.get(), LOOPS],
]), self.tys,
),
&mut self.ci.nodes, &mut self.ci.nodes,
); );
self.ci.loops.push(Loop { self.ci.loops.push(Loop {
@ -3552,9 +3638,12 @@ impl<'a> Codegen<'a> {
if let Some(con) = mem::take(con).unwrap(&mut self.ci.nodes) { if let Some(con) = mem::take(con).unwrap(&mut self.ci.nodes) {
self.ci.ctrl.set( self.ci.ctrl.set(
self.ci self.ci.nodes.new_node(
.nodes ty::Id::VOID,
.new_node(ty::Id::VOID, Kind::Region, [con, self.ci.ctrl.get()]), Kind::Region,
[con, self.ci.ctrl.get()],
self.tys,
),
&mut self.ci.nodes, &mut self.ci.nodes,
); );
self.ci.nodes.merge_scopes( self.ci.nodes.merge_scopes(
@ -3562,6 +3651,7 @@ impl<'a> Codegen<'a> {
&self.ci.ctrl, &self.ci.ctrl,
&mut self.ci.scope, &mut self.ci.scope,
&mut cons, &mut cons,
self.tys,
); );
cons.clear(&mut self.ci.nodes); cons.clear(&mut self.ci.nodes);
} }
@ -3721,7 +3811,7 @@ impl<'a> Codegen<'a> {
bres.clear(&mut self.ci.nodes); bres.clear(&mut self.ci.nodes);
self.ci.nodes.unlock(node); self.ci.nodes.unlock(node);
let rpl = self.ci.nodes.late_peephole(node).unwrap_or(node); let rpl = self.ci.nodes.late_peephole(node, self.tys).unwrap_or(node);
if self.ci.ctrl.get() == node { if self.ci.ctrl.get() == node {
self.ci.ctrl.set_remove(rpl, &mut self.ci.nodes); self.ci.ctrl.set_remove(rpl, &mut self.ci.nodes);
} }
@ -3734,8 +3824,12 @@ impl<'a> Codegen<'a> {
let mut cnd = self.expr_ctx(cond, Ctx::default().with_ty(ty::Id::BOOL))?; let mut cnd = self.expr_ctx(cond, Ctx::default().with_ty(ty::Id::BOOL))?;
self.assert_ty(cond.pos(), &mut cnd, ty::Id::BOOL, "condition"); self.assert_ty(cond.pos(), &mut cnd, ty::Id::BOOL, "condition");
let if_node = let if_node = self.ci.nodes.new_node(
self.ci.nodes.new_node(ty::Id::VOID, Kind::If, [self.ci.ctrl.get(), cnd.id]); ty::Id::VOID,
Kind::If,
[self.ci.ctrl.get(), cnd.id],
self.tys,
);
'b: { 'b: {
let branch = match self.ci.nodes[if_node].ty { let branch = match self.ci.nodes[if_node].ty {
@ -3756,14 +3850,14 @@ impl<'a> Codegen<'a> {
let else_scope = self.ci.scope.dup(&mut self.ci.nodes); let else_scope = self.ci.scope.dup(&mut self.ci.nodes);
self.ci.ctrl.set( self.ci.ctrl.set(
self.ci.nodes.new_node(ty::Id::VOID, Kind::Then, [if_node]), self.ci.nodes.new_node(ty::Id::VOID, Kind::Then, [if_node], self.tys),
&mut self.ci.nodes, &mut self.ci.nodes,
); );
let lcntrl = self.expr(then).map_or(Nid::MAX, |_| self.ci.ctrl.get()); let lcntrl = self.expr(then).map_or(Nid::MAX, |_| self.ci.ctrl.get());
let mut then_scope = mem::replace(&mut self.ci.scope, else_scope); let mut then_scope = mem::replace(&mut self.ci.scope, else_scope);
self.ci.ctrl.set( self.ci.ctrl.set(
self.ci.nodes.new_node(ty::Id::VOID, Kind::Else, [if_node]), self.ci.nodes.new_node(ty::Id::VOID, Kind::Else, [if_node], self.tys),
&mut self.ci.nodes, &mut self.ci.nodes,
); );
let rcntrl = if let Some(else_) = else_ { let rcntrl = if let Some(else_) = else_ {
@ -3786,7 +3880,7 @@ impl<'a> Codegen<'a> {
} }
self.ci.ctrl.set( self.ci.ctrl.set(
self.ci.nodes.new_node(ty::Id::VOID, Kind::Region, [lcntrl, rcntrl]), self.ci.nodes.new_node(ty::Id::VOID, Kind::Region, [lcntrl, rcntrl], self.tys),
&mut self.ci.nodes, &mut self.ci.nodes,
); );
@ -3795,6 +3889,7 @@ impl<'a> Codegen<'a> {
&self.ci.ctrl, &self.ci.ctrl,
&mut self.ci.scope, &mut self.ci.scope,
&mut then_scope, &mut then_scope,
self.tys,
); );
then_scope.clear(&mut self.ci.nodes); then_scope.clear(&mut self.ci.nodes);
@ -3809,7 +3904,7 @@ impl<'a> Codegen<'a> {
fn gen_global(&mut self, global: ty::Global) -> Option<Value> { fn gen_global(&mut self, global: ty::Global) -> Option<Value> {
let gl = &self.tys.ins.globals[global]; let gl = &self.tys.ins.globals[global];
let value = self.ci.nodes.new_node(gl.ty, Kind::Global { global }, [VOID]); let value = self.ci.nodes.new_node_nop(gl.ty, Kind::Global { global }, [VOID]);
self.ci.nodes[value].aclass = GLOBAL_ACLASS as _; self.ci.nodes[value].aclass = GLOBAL_ACLASS as _;
Some(Value::ptr(value).ty(gl.ty)) Some(Value::ptr(value).ty(gl.ty))
} }
@ -3876,7 +3971,8 @@ impl<'a> Codegen<'a> {
_ if ty.is_pointer() || ty.is_integer() || ty == ty::Id::BOOL => { _ if ty.is_pointer() || ty.is_integer() || ty == ty::Id::BOOL => {
let lhs = self.load_mem(lhs, ty); let lhs = self.load_mem(lhs, ty);
let rhs = self.load_mem(rhs, ty); let rhs = self.load_mem(rhs, ty);
let res = self.ci.nodes.new_node(ty, Kind::BinOp { op }, [VOID, lhs, rhs]); let res =
self.ci.nodes.new_node(ty, Kind::BinOp { op }, [VOID, lhs, rhs], self.tys);
self.store_mem(dst, ty, res); self.store_mem(dst, ty, res);
} }
ty::Kind::Struct(is) => { ty::Kind::Struct(is) => {
@ -4032,7 +4128,8 @@ impl<'a> Codegen<'a> {
let off = self.ci.nodes.new_const(ty::Id::INT, off); let off = self.ci.nodes.new_const(ty::Id::INT, off);
let aclass = self.ci.nodes.aclass_index(val).1; let aclass = self.ci.nodes.aclass_index(val).1;
let inps = [VOID, val, off]; let inps = [VOID, val, off];
let seted = self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Add }, inps); let seted =
self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Add }, inps, self.tys);
self.ci.nodes.pass_aclass(aclass, seted); self.ci.nodes.pass_aclass(aclass, seted);
seted seted
} }
@ -4053,16 +4150,24 @@ impl<'a> Codegen<'a> {
if loob.ctrl[id].is_live() { if loob.ctrl[id].is_live() {
loob.ctrl[id].set( loob.ctrl[id].set(
self.ci.nodes.new_node(ty::Id::VOID, Kind::Region, [ self.ci.nodes.new_node(
self.ci.ctrl.get(), ty::Id::VOID,
loob.ctrl[id].get(), Kind::Region,
]), [self.ci.ctrl.get(), loob.ctrl[id].get()],
self.tys,
),
&mut self.ci.nodes, &mut self.ci.nodes,
); );
let mut scope = mem::take(&mut loob.ctrl_scope[id]); let mut scope = mem::take(&mut loob.ctrl_scope[id]);
let ctrl = mem::take(&mut loob.ctrl[id]); let ctrl = mem::take(&mut loob.ctrl[id]);
self.ci.nodes.merge_scopes(&mut self.ci.loops, &ctrl, &mut scope, &mut self.ci.scope); self.ci.nodes.merge_scopes(
&mut self.ci.loops,
&ctrl,
&mut scope,
&mut self.ci.scope,
self.tys,
);
loob = self.ci.loops.last_mut().unwrap(); loob = self.ci.loops.last_mut().unwrap();
loob.ctrl_scope[id] = scope; loob.ctrl_scope[id] = scope;
@ -4274,6 +4379,8 @@ impl<'a> Codegen<'a> {
self.ci.nodes.gcm(&mut self.pool.nid_stack, &mut self.pool.nid_set); self.ci.nodes.gcm(&mut self.pool.nid_stack, &mut self.pool.nid_set);
self.ci.nodes.basic_blocks(); self.ci.nodes.basic_blocks();
self.ci.nodes.graphviz(self.ty_display(ty::Id::VOID)); self.ci.nodes.graphviz(self.ty_display(ty::Id::VOID));
} else {
self.ci.nodes.graphviz_in_browser(self.ty_display(ty::Id::VOID));
} }
self.errors.borrow().len() == prev_err_len self.errors.borrow().len() == prev_err_len
@ -4317,10 +4424,12 @@ impl<'a> Codegen<'a> {
&& let Some(elem) = self.tys.base_of(upcasted) && let Some(elem) = self.tys.base_of(upcasted)
{ {
let cnst = self.ci.nodes.new_const(ty::Id::INT, self.tys.size_of(elem)); let cnst = self.ci.nodes.new_const(ty::Id::INT, self.tys.size_of(elem));
oper.id = oper.id = self.ci.nodes.new_node(
self.ci.nodes.new_node(upcasted, Kind::BinOp { op: TokenKind::Mul }, [ upcasted,
VOID, oper.id, cnst, Kind::BinOp { op: TokenKind::Mul },
]); [VOID, oper.id, cnst],
self.tys,
);
return (upcasted, self.ci.nodes.aclass_index(other.id).1); return (upcasted, self.ci.nodes.aclass_index(other.id).1);
} }
} }
@ -4355,10 +4464,12 @@ impl<'a> Codegen<'a> {
// registers have inverted offsets so that accessing the inner type is a noop // registers have inverted offsets so that accessing the inner type is a noop
let flag_offset = self.tys.size_of(oty) * 8 - flag_offset * 8 - 1; let flag_offset = self.tys.size_of(oty) * 8 - flag_offset * 8 - 1;
let fill = self.ci.nodes.new_const(oty, 1i64 << flag_offset); let fill = self.ci.nodes.new_const(oty, 1i64 << flag_offset);
val.id = self val.id = self.ci.nodes.new_node(
.ci oty,
.nodes Kind::BinOp { op: TokenKind::Bor },
.new_node(oty, Kind::BinOp { op: TokenKind::Bor }, [VOID, val.id, fill]); [VOID, val.id, fill],
self.tys,
);
val.ty = oty; val.ty = oty;
} }
Loc::Stack => { Loc::Stack => {
@ -4396,7 +4507,7 @@ impl<'a> Codegen<'a> {
// TODO: extract the if check int a fucntion // TODO: extract the if check int a fucntion
self.ci.ctrl.set( self.ci.ctrl.set(
self.ci.nodes.new_node(oty, Kind::Assert { kind, pos }, [ self.ci.nodes.new_node_nop(oty, Kind::Assert { kind, pos }, [
self.ci.ctrl.get(), self.ci.ctrl.get(),
null_check, null_check,
opt.id, opt.id,
@ -4430,7 +4541,7 @@ impl<'a> Codegen<'a> {
Loc::Reg => { Loc::Reg => {
self.strip_ptr(&mut cmped); self.strip_ptr(&mut cmped);
let inps = [VOID, cmped.id, self.ci.nodes.new_const(cmped.ty, 0)]; let inps = [VOID, cmped.id, self.ci.nodes.new_const(cmped.ty, 0)];
self.ci.nodes.new_node(ty::Id::BOOL, Kind::BinOp { op }, inps) self.ci.nodes.new_node(ty::Id::BOOL, Kind::BinOp { op }, inps, self.tys)
} }
Loc::Stack => { Loc::Stack => {
cmped.id = self.offset(cmped.id, flag_offset); cmped.id = self.offset(cmped.id, flag_offset);
@ -4438,7 +4549,7 @@ impl<'a> Codegen<'a> {
debug_assert!(cmped.ptr); debug_assert!(cmped.ptr);
self.strip_ptr(&mut cmped); self.strip_ptr(&mut cmped);
let inps = [VOID, cmped.id, self.ci.nodes.new_const(flag_ty, 0)]; let inps = [VOID, cmped.id, self.ci.nodes.new_const(flag_ty, 0)];
self.ci.nodes.new_node(ty::Id::BOOL, Kind::BinOp { op }, inps) self.ci.nodes.new_node(ty::Id::BOOL, Kind::BinOp { op }, inps, self.tys)
} }
} }
} }
@ -4501,7 +4612,8 @@ impl<'a> Codegen<'a> {
self.strip_ptr(value); self.strip_ptr(value);
let mask = self.ci.nodes.new_const(to, (1i64 << (self.tys.size_of(value.ty) * 8)) - 1); let mask = self.ci.nodes.new_const(to, (1i64 << (self.tys.size_of(value.ty) * 8)) - 1);
let inps = [VOID, value.id, mask]; let inps = [VOID, value.id, mask];
*value = self.ci.nodes.new_node_lit(to, Kind::BinOp { op: TokenKind::Band }, inps); *value =
self.ci.nodes.new_node_lit(to, Kind::BinOp { op: TokenKind::Band }, inps, self.tys);
value.ty = to; value.ty = to;
} }
@ -4680,6 +4792,7 @@ mod tests {
fb_driver; fb_driver;
// Purely Testing Examples; // Purely Testing Examples;
storing_into_nullable_struct;
scheduling_block_did_dirty; scheduling_block_did_dirty;
null_check_returning_small_global; null_check_returning_small_global;
null_check_in_the_loop; null_check_in_the_loop;