fixing loop bugs and some optimization edgecases
This commit is contained in:
parent
8528bef8cf
commit
ad4aed9c98
|
@ -375,7 +375,10 @@ main := fn(): int {
|
||||||
return @inline(foo, 1, 2, 3) - 6
|
return @inline(foo, 1, 2, 3) - 6
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gb := 0
|
||||||
|
|
||||||
foo := fn(a: int, b: int, c: int): int {
|
foo := fn(a: int, b: int, c: int): int {
|
||||||
|
if gb != 0 return 1
|
||||||
return a + b + c
|
return a + b + c
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -777,13 +780,14 @@ screenidx := fn(orange: int): int {
|
||||||
// in module: random.hb
|
// in module: random.hb
|
||||||
|
|
||||||
integer := fn(min: int, max: int): int {
|
integer := fn(min: int, max: int): int {
|
||||||
rng := @as(int, @eca(3, 4))
|
rng := @as(int, 4)
|
||||||
|
|
||||||
if min != 0 | max != 0 {
|
if max == 0 {
|
||||||
return rng % (max - min + 1) + min
|
return rng % (max - min + 1) + min
|
||||||
}
|
} else {
|
||||||
return rng
|
return rng
|
||||||
}
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### inlined_generic_functions
|
#### inlined_generic_functions
|
||||||
|
|
|
@ -974,7 +974,7 @@ impl Codegen {
|
||||||
|
|
||||||
let fuc = &self.tys.ins.funcs[func as usize];
|
let fuc = &self.tys.ins.funcs[func as usize];
|
||||||
let ast = self.files[fuc.file as usize].clone();
|
let ast = self.files[fuc.file as usize].clone();
|
||||||
let &E::Closure { args: cargs, body, .. } = fuc.expr.get(&ast).unwrap() else {
|
let &E::Closure { args: cargs, body, .. } = fuc.expr.get(&ast) else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1398,7 +1398,7 @@ impl Codegen {
|
||||||
|
|
||||||
let fuc = &self.tys.ins.funcs[func as usize];
|
let fuc = &self.tys.ins.funcs[func as usize];
|
||||||
let ast = self.files[fuc.file as usize].clone();
|
let ast = self.files[fuc.file as usize].clone();
|
||||||
let &E::Closure { args: cargs, .. } = fuc.expr.get(&ast).unwrap() else {
|
let &E::Closure { args: cargs, .. } = fuc.expr.get(&ast) else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1803,7 +1803,7 @@ impl Codegen {
|
||||||
fn compute_signature(&mut self, func: &mut ty::Func, pos: Pos, args: &[Expr]) -> Option<Sig> {
|
fn compute_signature(&mut self, func: &mut ty::Func, pos: Pos, args: &[Expr]) -> Option<Sig> {
|
||||||
let fuc = &self.tys.ins.funcs[*func as usize];
|
let fuc = &self.tys.ins.funcs[*func as usize];
|
||||||
let fast = self.files[fuc.file as usize].clone();
|
let fast = self.files[fuc.file as usize].clone();
|
||||||
let &Expr::Closure { args: cargs, ret, .. } = fuc.expr.get(&fast).unwrap() else {
|
let &Expr::Closure { args: cargs, ret, .. } = fuc.expr.get(&fast) else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2122,7 +2122,7 @@ impl Codegen {
|
||||||
debug_assert!(func.file == file);
|
debug_assert!(func.file == file);
|
||||||
let sig = func.sig.unwrap();
|
let sig = func.sig.unwrap();
|
||||||
let ast = self.files[file as usize].clone();
|
let ast = self.files[file as usize].clone();
|
||||||
let expr = func.expr.get(&ast).unwrap();
|
let expr = func.expr.get(&ast);
|
||||||
let ct_stack_base = self.ct.vm.read_reg(reg::STACK_PTR).0;
|
let ct_stack_base = self.ct.vm.read_reg(reg::STACK_PTR).0;
|
||||||
|
|
||||||
let repl = ItemCtx { file, ret: Some(sig.ret), ..self.pool.cis.pop().unwrap_or_default() };
|
let repl = ItemCtx { file, ret: Some(sig.ret), ..self.pool.cis.pop().unwrap_or_default() };
|
||||||
|
@ -2428,9 +2428,7 @@ impl Codegen {
|
||||||
match *trap {
|
match *trap {
|
||||||
trap::Trap::MakeStruct(trap::MakeStruct { file, struct_expr }) => {
|
trap::Trap::MakeStruct(trap::MakeStruct { file, struct_expr }) => {
|
||||||
let cfile = self.files[file as usize].clone();
|
let cfile = self.files[file as usize].clone();
|
||||||
let &Expr::Struct { fields, captured, packed, .. } =
|
let &Expr::Struct { fields, captured, packed, .. } = struct_expr.get(&cfile) else {
|
||||||
struct_expr.get(&cfile).unwrap()
|
|
||||||
else {
|
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -280,11 +280,22 @@ impl TokenKind {
|
||||||
Self::Eq => (a == b) as i64,
|
Self::Eq => (a == b) as i64,
|
||||||
Self::Ne => (a != b) as i64,
|
Self::Ne => (a != b) as i64,
|
||||||
Self::Band => a & b,
|
Self::Band => a & b,
|
||||||
|
Self::Bor => a | b,
|
||||||
|
Self::Mod => a % b,
|
||||||
Self::Shr => a >> b,
|
Self::Shr => a >> b,
|
||||||
s => todo!("{s}"),
|
s => todo!("{s}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn cmp_against(self) -> Option<u64> {
|
||||||
|
Some(match self {
|
||||||
|
TokenKind::Le | TokenKind::Gt => 1,
|
||||||
|
TokenKind::Ne | TokenKind::Eq => 0,
|
||||||
|
TokenKind::Ge | TokenKind::Lt => (-1i64) as _,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_homogenous(&self) -> bool {
|
pub fn is_homogenous(&self) -> bool {
|
||||||
self.precedence() != Self::Eq.precedence()
|
self.precedence() != Self::Eq.precedence()
|
||||||
&& self.precedence() != Self::Gt.precedence()
|
&& self.precedence() != Self::Gt.precedence()
|
||||||
|
|
|
@ -395,6 +395,16 @@ mod ty {
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn extend(self) -> Self {
|
||||||
|
if self.is_signed() {
|
||||||
|
Self::INT
|
||||||
|
} else if self.is_pointer() {
|
||||||
|
self
|
||||||
|
} else {
|
||||||
|
Self::UINT
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Default, Debug, Clone, Copy)]
|
#[derive(PartialEq, Eq, Default, Debug, Clone, Copy)]
|
||||||
|
|
|
@ -1125,12 +1125,12 @@ impl ExprRef {
|
||||||
Self(NonNull::from(expr).cast())
|
Self(NonNull::from(expr).cast())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get<'a>(&self, from: &'a Ast) -> Option<&'a Expr<'a>> {
|
pub fn get<'a>(&self, from: &'a Ast) -> &'a Expr<'a> {
|
||||||
from.mem.contains(self.0.as_ptr() as _).then_some(())?;
|
assert!(from.mem.contains(self.0.as_ptr() as _));
|
||||||
// SAFETY: the pointer is or was a valid reference in the past, if it points within one of
|
// SAFETY: the pointer is or was a valid reference in the past, if it points within one of
|
||||||
// arenas regions, it muts be walid, since arena does not give invalid pointers to its
|
// arenas regions, it muts be walid, since arena does not give invalid pointers to its
|
||||||
// allocations
|
// allocations
|
||||||
Some(unsafe { { self.0 }.as_ref() })
|
unsafe { { self.0 }.as_ref() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dangling() -> Self {
|
pub fn dangling() -> Self {
|
||||||
|
|
388
lang/src/son.rs
388
lang/src/son.rs
|
@ -394,6 +394,16 @@ impl Nodes {
|
||||||
return Some(self[target].inputs[1]);
|
return Some(self[target].inputs[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
K::Loop => {
|
||||||
|
if self[target].inputs[1] == NEVER {
|
||||||
|
for o in self[target].outputs.clone() {
|
||||||
|
if self[o].kind == Kind::Phi {
|
||||||
|
self.replace(o, self[o].inputs[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Some(self[target].inputs[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,6 +440,7 @@ impl Nodes {
|
||||||
hash_map::RawEntryMut::Occupied(other) => {
|
hash_map::RawEntryMut::Occupied(other) => {
|
||||||
let rpl = other.get_key_value().0.value;
|
let rpl = other.get_key_value().0.value;
|
||||||
self[target].inputs[inp_index] = prev;
|
self[target].inputs[inp_index] = prev;
|
||||||
|
self.lookup.insert(target.key(&self.values), target, &self.values);
|
||||||
self.replace(target, rpl);
|
self.replace(target, rpl);
|
||||||
rpl
|
rpl
|
||||||
}
|
}
|
||||||
|
@ -680,7 +691,6 @@ impl Nodes {
|
||||||
climb_impl(self, from, &mut for_each)
|
climb_impl(self, from, &mut for_each)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(dead_code)]
|
|
||||||
fn late_peephole(&mut self, target: Nid) -> Nid {
|
fn late_peephole(&mut self, target: Nid) -> Nid {
|
||||||
if let Some(id) = self.peephole(target) {
|
if let Some(id) = self.peephole(target) {
|
||||||
self.replace(target, id);
|
self.replace(target, id);
|
||||||
|
@ -695,7 +705,7 @@ impl Nodes {
|
||||||
l.scope
|
l.scope
|
||||||
.vars
|
.vars
|
||||||
.get_mut(index)
|
.get_mut(index)
|
||||||
.map_or((ty::Id::VOID, &mut l.scope.store), |v| (v.ty, &mut v.value))
|
.map_or((0, ty::Id::VOID, &mut l.scope.store), |v| (v.id, v.ty, &mut v.value))
|
||||||
},
|
},
|
||||||
value,
|
value,
|
||||||
loops,
|
loops,
|
||||||
|
@ -703,12 +713,12 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_loop_store(&mut self, value: &mut Nid, loops: &mut [Loop]) {
|
fn load_loop_store(&mut self, value: &mut Nid, loops: &mut [Loop]) {
|
||||||
self.load_loop_value(&mut |l| (ty::Id::VOID, &mut l.scope.store), value, loops);
|
self.load_loop_value(&mut |l| (0, ty::Id::VOID, &mut l.scope.store), value, loops);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_loop_value(
|
fn load_loop_value(
|
||||||
&mut self,
|
&mut self,
|
||||||
get_lvalue: &mut impl FnMut(&mut Loop) -> (ty::Id, &mut Nid),
|
get_lvalue: &mut impl FnMut(&mut Loop) -> (Ident, ty::Id, &mut Nid),
|
||||||
value: &mut Nid,
|
value: &mut Nid,
|
||||||
loops: &mut [Loop],
|
loops: &mut [Loop],
|
||||||
) {
|
) {
|
||||||
|
@ -716,13 +726,13 @@ impl Nodes {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let [loob, loops @ ..] = loops else { unreachable!() };
|
let [loops @ .., loob] = loops else { unreachable!() };
|
||||||
let node = loob.node;
|
let node = loob.node;
|
||||||
let (ty, lvalue) = get_lvalue(loob);
|
let (_id, ty, lvalue) = get_lvalue(loob);
|
||||||
|
|
||||||
self.load_loop_value(get_lvalue, lvalue, loops);
|
self.load_loop_value(get_lvalue, lvalue, loops);
|
||||||
|
|
||||||
if !self[*lvalue].is_lazy_phi() {
|
if !self[*lvalue].is_lazy_phi(node) {
|
||||||
self.unlock(*value);
|
self.unlock(*value);
|
||||||
let inps = [node, *lvalue, VOID];
|
let inps = [node, *lvalue, VOID];
|
||||||
self.unlock(*lvalue);
|
self.unlock(*lvalue);
|
||||||
|
@ -796,10 +806,14 @@ impl Nodes {
|
||||||
self.unlock_remove(load);
|
self.unlock_remove(load);
|
||||||
}
|
}
|
||||||
for var in &scope.vars {
|
for var in &scope.vars {
|
||||||
|
if self[var.value].kind == Kind::Arg {
|
||||||
|
self.unlock(var.value);
|
||||||
|
} else {
|
||||||
self.unlock_remove(var.value);
|
self.unlock_remove(var.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ops::Index<Nid> for Nodes {
|
impl ops::Index<Nid> for Nodes {
|
||||||
type Output = Node;
|
type Output = Node;
|
||||||
|
@ -933,12 +947,13 @@ impl Node {
|
||||||
(self.kind, &self.inputs, self.ty)
|
(self.kind, &self.inputs, self.ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_lazy_phi(&self) -> bool {
|
fn is_lazy_phi(&self, loob: Nid) -> bool {
|
||||||
self.kind == Kind::Phi && self.inputs[2] == 0
|
self.kind == Kind::Phi && self.inputs[2] == 0 && self.inputs[0] == loob
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_not_gvnd(&self) -> bool {
|
fn is_not_gvnd(&self) -> bool {
|
||||||
self.is_lazy_phi() || matches!(self.kind, Kind::Arg | Kind::Stck)
|
(self.kind == Kind::Phi && self.inputs[2] == 0)
|
||||||
|
|| matches!(self.kind, Kind::Arg | Kind::Stck)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -970,11 +985,12 @@ struct Scope {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scope {
|
impl Scope {
|
||||||
pub fn iter_elems_mut(&mut self) -> impl Iterator<Item = (ty::Id, &mut Nid)> {
|
pub fn iter_elems_mut(&mut self) -> impl Iterator<Item = (Ident, ty::Id, &mut Nid)> {
|
||||||
self.vars
|
self.vars.iter_mut().map(|v| (v.id, v.ty, &mut v.value)).chain(core::iter::once((
|
||||||
.iter_mut()
|
0,
|
||||||
.map(|v| (v.ty, &mut v.value))
|
ty::Id::VOID,
|
||||||
.chain(core::iter::once((ty::Id::VOID, &mut self.store)))
|
&mut self.store,
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -983,6 +999,8 @@ struct ItemCtx {
|
||||||
file: FileId,
|
file: FileId,
|
||||||
ret: Option<ty::Id>,
|
ret: Option<ty::Id>,
|
||||||
task_base: usize,
|
task_base: usize,
|
||||||
|
inline_depth: u16,
|
||||||
|
inline_ret: Option<(Value, Nid)>,
|
||||||
nodes: Nodes,
|
nodes: Nodes,
|
||||||
ctrl: Nid,
|
ctrl: Nid,
|
||||||
call_count: u16,
|
call_count: u16,
|
||||||
|
@ -1075,6 +1093,22 @@ impl ItemCtx {
|
||||||
*saved_regs.entry(hvenc).or_insert(would_insert)
|
*saved_regs.entry(hvenc).or_insert(would_insert)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut parama = tys.parama(sig.ret);
|
||||||
|
|
||||||
|
for (ti, &arg) in sig.args.range().zip(fuc.nodes[VOID].outputs.iter().skip(2)) {
|
||||||
|
let ty = tys.ins.args[ti];
|
||||||
|
if tys.size_of(ty) == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let size @ 9..=16 = tys.size_of(ty) {
|
||||||
|
let rg = parama.next_wide();
|
||||||
|
self.emit(instrs::st(rg, reg::STACK_PTR, fuc.nodes[arg].offset as _, size as _));
|
||||||
|
self.emit(instrs::addi64(rg, reg::STACK_PTR, fuc.nodes[arg].offset as _));
|
||||||
|
} else {
|
||||||
|
parama.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (i, block) in fuc.blocks.iter().enumerate() {
|
for (i, block) in fuc.blocks.iter().enumerate() {
|
||||||
let blk = regalloc2::Block(i as _);
|
let blk = regalloc2::Block(i as _);
|
||||||
fuc.nodes[block.nid].offset = self.code.len() as _;
|
fuc.nodes[block.nid].offset = self.code.len() as _;
|
||||||
|
@ -1093,31 +1127,46 @@ impl ItemCtx {
|
||||||
};
|
};
|
||||||
let allocs = ralloc.ctx.output.inst_allocs(inst);
|
let allocs = ralloc.ctx.output.inst_allocs(inst);
|
||||||
let node = &fuc.nodes[nid];
|
let node = &fuc.nodes[nid];
|
||||||
|
|
||||||
|
let mut extend = |base: ty::Id, dest: ty::Id, from: usize, to: usize| {
|
||||||
|
if base.simple_size() == dest.simple_size() {
|
||||||
|
return Default::default();
|
||||||
|
}
|
||||||
|
match (base.is_signed(), dest.is_signed()) {
|
||||||
|
(true, true) => {
|
||||||
|
let op = [instrs::sxt8, instrs::sxt16, instrs::sxt32]
|
||||||
|
[base.simple_size().unwrap().ilog2() as usize];
|
||||||
|
op(atr(allocs[to]), atr(allocs[from]))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let mask = (1u64 << (base.simple_size().unwrap() * 8)) - 1;
|
||||||
|
instrs::andi(atr(allocs[to]), atr(allocs[from]), mask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
match node.kind {
|
match node.kind {
|
||||||
Kind::If => {
|
Kind::If => {
|
||||||
let &[_, cond] = node.inputs.as_slice() else { unreachable!() };
|
let &[_, cnd] = node.inputs.as_slice() else { unreachable!() };
|
||||||
if let Kind::BinOp { op } = fuc.nodes[cond].kind
|
if let Kind::BinOp { op } = fuc.nodes[cnd].kind
|
||||||
&& let Some((op, swapped)) = op.cond_op(node.ty.is_signed())
|
&& let Some((op, swapped)) = op.cond_op(node.ty.is_signed())
|
||||||
{
|
{
|
||||||
let &[lhs, rhs] = allocs else { unreachable!() };
|
let &[lhs, rhs] = allocs else { unreachable!() };
|
||||||
let &[_, lhsn, rhsn] = fuc.nodes[cond].inputs.as_slice() else {
|
let &[_, lh, rh] = fuc.nodes[cnd].inputs.as_slice() else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
let lhsn_size = fuc.nodes[lhsn].ty.simple_size().unwrap() as u64;
|
|
||||||
if lhsn_size < 8 {
|
self.emit(extend(fuc.nodes[lh].ty, fuc.nodes[lh].ty.extend(), 0, 0));
|
||||||
let mask = (1u64 << (lhsn_size * 8)) - 1;
|
self.emit(extend(fuc.nodes[rh].ty, fuc.nodes[rh].ty.extend(), 1, 1));
|
||||||
self.emit(instrs::andi(atr(lhs), atr(lhs), mask));
|
|
||||||
}
|
|
||||||
let rhsn_size = fuc.nodes[rhsn].ty.simple_size().unwrap() as u64;
|
|
||||||
if rhsn_size < 8 {
|
|
||||||
let mask = (1u64 << (rhsn_size * 8)) - 1;
|
|
||||||
self.emit(instrs::andi(atr(rhs), atr(rhs), mask));
|
|
||||||
}
|
|
||||||
let rel = Reloc::new(self.code.len(), 3, 2);
|
let rel = Reloc::new(self.code.len(), 3, 2);
|
||||||
self.jump_relocs.push((node.outputs[!swapped as usize], rel));
|
self.jump_relocs.push((node.outputs[!swapped as usize], rel));
|
||||||
self.emit(op(atr(lhs), atr(rhs), 0));
|
self.emit(op(atr(lhs), atr(rhs), 0));
|
||||||
} else {
|
} else {
|
||||||
todo!()
|
self.emit(extend(fuc.nodes[cnd].ty, fuc.nodes[cnd].ty.extend(), 0, 0));
|
||||||
|
let rel = Reloc::new(self.code.len(), 3, 2);
|
||||||
|
self.jump_relocs.push((node.outputs[1], rel));
|
||||||
|
self.emit(instrs::jne(atr(allocs[0]), reg::ZERO, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kind::Loop | Kind::Region => {
|
Kind::Loop | Kind::Region => {
|
||||||
|
@ -1155,23 +1204,14 @@ impl ItemCtx {
|
||||||
let base = fuc.nodes[node.inputs[1]].ty;
|
let base = fuc.nodes[node.inputs[1]].ty;
|
||||||
let dest = node.ty;
|
let dest = node.ty;
|
||||||
|
|
||||||
match (base.is_signed(), dest.is_signed()) {
|
self.emit(extend(base, dest, 1, 0))
|
||||||
(true, true) => {
|
|
||||||
let op = [instrs::sxt8, instrs::sxt16, instrs::sxt32]
|
|
||||||
[tys.size_of(base).ilog2() as usize];
|
|
||||||
self.emit(op(atr(allocs[0]), atr(allocs[1])))
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let mask = (1u64 << (tys.size_of(base) * 8)) - 1;
|
|
||||||
self.emit(instrs::andi(atr(allocs[0]), atr(allocs[1]), mask));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Kind::UnOp { op } => {
|
Kind::UnOp { op } => {
|
||||||
let op = op.unop().expect("TODO: unary operator not supported");
|
let op = op.unop().expect("TODO: unary operator not supported");
|
||||||
let &[dst, oper] = allocs else { unreachable!() };
|
let &[dst, oper] = allocs else { unreachable!() };
|
||||||
self.emit(op(atr(dst), atr(oper)));
|
self.emit(op(atr(dst), atr(oper)));
|
||||||
}
|
}
|
||||||
|
Kind::BinOp { .. } if node.lock_rc != 0 => {}
|
||||||
Kind::BinOp { op } => {
|
Kind::BinOp { op } => {
|
||||||
let &[.., rhs] = node.inputs.as_slice() else { unreachable!() };
|
let &[.., rhs] = node.inputs.as_slice() else { unreachable!() };
|
||||||
|
|
||||||
|
@ -1187,9 +1227,19 @@ impl ItemCtx {
|
||||||
{
|
{
|
||||||
let &[dst, lhs, rhs] = allocs else { unreachable!() };
|
let &[dst, lhs, rhs] = allocs else { unreachable!() };
|
||||||
self.emit(op(atr(dst), atr(lhs), atr(rhs)));
|
self.emit(op(atr(dst), atr(lhs), atr(rhs)));
|
||||||
} else if op.cond_op(node.ty.is_signed()).is_some() {
|
} else if let Some(against) = op.cmp_against() {
|
||||||
} else {
|
let &[_, lh, rh] = node.inputs.as_slice() else { unreachable!() };
|
||||||
todo!()
|
self.emit(extend(fuc.nodes[lh].ty, fuc.nodes[lh].ty.extend(), 0, 0));
|
||||||
|
self.emit(extend(fuc.nodes[rh].ty, fuc.nodes[rh].ty.extend(), 1, 1));
|
||||||
|
|
||||||
|
let signed = fuc.nodes[lh].ty.is_signed();
|
||||||
|
let op_fn = if signed { instrs::cmps } else { instrs::cmpu };
|
||||||
|
let &[dst, lhs, rhs] = allocs else { unreachable!() };
|
||||||
|
self.emit(op_fn(atr(dst), atr(lhs), atr(rhs)));
|
||||||
|
self.emit(instrs::cmpui(atr(dst), atr(dst), against));
|
||||||
|
if matches!(op, TokenKind::Eq | TokenKind::Lt | TokenKind::Gt) {
|
||||||
|
self.emit(instrs::not(atr(dst), atr(dst)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kind::Call { func } => {
|
Kind::Call { func } => {
|
||||||
|
@ -1280,9 +1330,9 @@ impl ItemCtx {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_body(&mut self, tys: &mut Types, files: &[parser::Ast], sig: Sig) {
|
fn emit_body(&mut self, tys: &mut Types, files: &[parser::Ast], sig: Sig) {
|
||||||
|
self.nodes.check_final_integrity();
|
||||||
self.nodes.graphviz(tys, files);
|
self.nodes.graphviz(tys, files);
|
||||||
self.nodes.gcm();
|
self.nodes.gcm();
|
||||||
self.nodes.check_final_integrity();
|
|
||||||
self.nodes.basic_blocks();
|
self.nodes.basic_blocks();
|
||||||
self.nodes.graphviz(tys, files);
|
self.nodes.graphviz(tys, files);
|
||||||
|
|
||||||
|
@ -1308,6 +1358,10 @@ impl ItemCtx {
|
||||||
|
|
||||||
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
|
||||||
|
&& self
|
||||||
|
.jump_relocs
|
||||||
|
.last()
|
||||||
|
.map_or(true, |&(r, _)| self.nodes[r].offset as usize != self.code.len())
|
||||||
{
|
{
|
||||||
self.code.truncate(self.code.len() - 5);
|
self.code.truncate(self.code.len() - 5);
|
||||||
self.ret_relocs.pop();
|
self.ret_relocs.pop();
|
||||||
|
@ -1316,6 +1370,7 @@ impl ItemCtx {
|
||||||
// FIXME: maybe do this incrementally
|
// FIXME: maybe do this incrementally
|
||||||
for (nd, rel) in self.jump_relocs.drain(..) {
|
for (nd, rel) in self.jump_relocs.drain(..) {
|
||||||
let offset = self.nodes[nd].offset;
|
let offset = self.nodes[nd].offset;
|
||||||
|
//debug_assert!(offset < self.code.len() as u32 - 1);
|
||||||
rel.apply_jump(&mut self.code, offset, 0);
|
rel.apply_jump(&mut self.code, offset, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1673,6 +1728,11 @@ impl<'a> Codegen<'a> {
|
||||||
Some(self.ci.nodes.new_node_lit(ty, Kind::Idk, [VOID]))
|
Some(self.ci.nodes.new_node_lit(ty, Kind::Idk, [VOID]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Expr::Bool { value, .. } => Some(self.ci.nodes.new_node_lit(
|
||||||
|
ty::Id::BOOL,
|
||||||
|
Kind::CInt { value: value as i64 },
|
||||||
|
[VOID],
|
||||||
|
)),
|
||||||
Expr::Number { value, .. } => Some(self.ci.nodes.new_node_lit(
|
Expr::Number { value, .. } => Some(self.ci.nodes.new_node_lit(
|
||||||
ctx.ty.filter(|ty| ty.is_integer()).unwrap_or(ty::Id::INT),
|
ctx.ty.filter(|ty| ty.is_integer()).unwrap_or(ty::Id::INT),
|
||||||
Kind::CInt { value },
|
Kind::CInt { value },
|
||||||
|
@ -1728,6 +1788,7 @@ impl<'a> Codegen<'a> {
|
||||||
let expected = *self.ci.ret.get_or_insert(value.ty);
|
let expected = *self.ci.ret.get_or_insert(value.ty);
|
||||||
self.assert_ty(pos, &mut value, expected, "return value");
|
self.assert_ty(pos, &mut value, expected, "return value");
|
||||||
|
|
||||||
|
if self.ci.inline_depth == 0 {
|
||||||
let mut inps = Vc::from([self.ci.ctrl, value.id]);
|
let mut inps = Vc::from([self.ci.ctrl, value.id]);
|
||||||
self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops);
|
self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops);
|
||||||
if let Some(str) = self.ci.scope.store.to_store() {
|
if let Some(str) = self.ci.scope.store.to_store() {
|
||||||
|
@ -1738,6 +1799,17 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
self.ci.nodes[NEVER].inputs.push(self.ci.ctrl);
|
self.ci.nodes[NEVER].inputs.push(self.ci.ctrl);
|
||||||
self.ci.nodes[self.ci.ctrl].outputs.push(NEVER);
|
self.ci.nodes[self.ci.ctrl].outputs.push(NEVER);
|
||||||
|
} else if let Some((pv, ctrl)) = &mut self.ci.inline_ret {
|
||||||
|
*ctrl =
|
||||||
|
self.ci.nodes.new_node(ty::Id::VOID, Kind::Region, [self.ci.ctrl, *ctrl]);
|
||||||
|
self.ci.ctrl = *ctrl;
|
||||||
|
self.ci.nodes.unlock(pv.id);
|
||||||
|
pv.id = self.ci.nodes.new_node(value.ty, Kind::Phi, [*ctrl, value.id, pv.id]);
|
||||||
|
self.ci.nodes.lock(pv.id);
|
||||||
|
} else {
|
||||||
|
self.ci.nodes.lock(value.id);
|
||||||
|
self.ci.inline_ret = Some((value, self.ci.ctrl));
|
||||||
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -1819,7 +1891,8 @@ impl<'a> Codegen<'a> {
|
||||||
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]))
|
||||||
}
|
}
|
||||||
Expr::BinOp { left, op: TokenKind::Decl, right } => {
|
Expr::BinOp { left, op: TokenKind::Decl, right } => {
|
||||||
let right = self.raw_expr(right)?;
|
let mut right = self.raw_expr(right)?;
|
||||||
|
self.strip_var(&mut right);
|
||||||
self.assign_pattern(left, right);
|
self.assign_pattern(left, right);
|
||||||
Some(Value::VOID)
|
Some(Value::VOID)
|
||||||
}
|
}
|
||||||
|
@ -1953,12 +2026,10 @@ impl<'a> Codegen<'a> {
|
||||||
let fuc = &self.tys.ins.funcs[fu as usize];
|
let fuc = &self.tys.ins.funcs[fu as usize];
|
||||||
let sig = fuc.sig.expect("TODO: generic functions");
|
let sig = fuc.sig.expect("TODO: generic functions");
|
||||||
let ast = &self.files[fuc.file as usize];
|
let ast = &self.files[fuc.file as usize];
|
||||||
let &Expr::Closure { args: cargs, .. } = fuc.expr.get(ast).unwrap() else {
|
let &Expr::Closure { args: cargs, .. } = fuc.expr.get(ast) else { unreachable!() };
|
||||||
unreachable!()
|
|
||||||
};
|
|
||||||
|
|
||||||
self.assert_report(
|
if args.len() != cargs.len() {
|
||||||
args.len() == cargs.len(),
|
self.report(
|
||||||
func.pos(),
|
func.pos(),
|
||||||
fa!(
|
fa!(
|
||||||
"expected {} function argumenr{}, got {}",
|
"expected {} function argumenr{}, got {}",
|
||||||
|
@ -1967,6 +2038,7 @@ impl<'a> Codegen<'a> {
|
||||||
args.len()
|
args.len()
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let mut inps = Vc::from([self.ci.ctrl]);
|
let mut inps = Vc::from([self.ci.ctrl]);
|
||||||
for ((arg, carg), tyx) in args.iter().zip(cargs).zip(sig.args.range()) {
|
for ((arg, carg), tyx) in args.iter().zip(cargs).zip(sig.args.range()) {
|
||||||
|
@ -1979,9 +2051,14 @@ impl<'a> Codegen<'a> {
|
||||||
debug_assert_ne!(value.id, 0);
|
debug_assert_ne!(value.id, 0);
|
||||||
self.assert_ty(arg.pos(), &mut value, ty, fa!("argument {}", carg.name));
|
self.assert_ty(arg.pos(), &mut value, ty, fa!("argument {}", carg.name));
|
||||||
|
|
||||||
|
self.ci.nodes.lock(value.id);
|
||||||
inps.push(value.id);
|
inps.push(value.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for &n in inps.iter().skip(1) {
|
||||||
|
self.ci.nodes.unlock(n);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(str) = self.ci.scope.store.to_store() {
|
if let Some(str) = self.ci.scope.store.to_store() {
|
||||||
inps.push(str);
|
inps.push(str);
|
||||||
}
|
}
|
||||||
|
@ -2012,6 +2089,82 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
alt_value.or(Some(Value::new(self.ci.ctrl).ty(sig.ret)))
|
alt_value.or(Some(Value::new(self.ci.ctrl).ty(sig.ret)))
|
||||||
}
|
}
|
||||||
|
Expr::Directive { name: "inline", args: [func, args @ ..], .. } => {
|
||||||
|
let ty = self.ty(func);
|
||||||
|
let ty::Kind::Func(fu) = ty.expand() else {
|
||||||
|
self.report(
|
||||||
|
func.pos(),
|
||||||
|
fa!(
|
||||||
|
"first argument to @inline should be a function,
|
||||||
|
but here its '{}'",
|
||||||
|
self.ty_display(ty)
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return Value::NEVER;
|
||||||
|
};
|
||||||
|
|
||||||
|
let fuc = &self.tys.ins.funcs[fu as usize];
|
||||||
|
let sig = fuc.sig.expect("TODO: generic functions");
|
||||||
|
let ast = &self.files[fuc.file as usize];
|
||||||
|
let &Expr::Closure { args: cargs, body, .. } = fuc.expr.get(ast) else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
if args.len() != cargs.len() {
|
||||||
|
self.report(
|
||||||
|
func.pos(),
|
||||||
|
fa!(
|
||||||
|
"expected {} inline function argumenr{}, got {}",
|
||||||
|
cargs.len(),
|
||||||
|
if cargs.len() == 1 { "" } else { "s" },
|
||||||
|
args.len()
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let arg_base = self.ci.scope.vars.len();
|
||||||
|
for ((arg, carg), tyx) in args.iter().zip(cargs).zip(sig.args.range()) {
|
||||||
|
let ty = self.tys.ins.args[tyx];
|
||||||
|
if self.tys.size_of(ty) == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut value = self.expr_ctx(arg, Ctx::default().with_ty(ty))?;
|
||||||
|
debug_assert_ne!(self.ci.nodes[value.id].kind, Kind::Stre);
|
||||||
|
debug_assert_ne!(value.id, 0);
|
||||||
|
self.assert_ty(arg.pos(), &mut value, ty, fa!("argument {}", carg.name));
|
||||||
|
|
||||||
|
self.ci.scope.vars.push(Variable {
|
||||||
|
id: carg.id,
|
||||||
|
ty,
|
||||||
|
ptr: value.ptr,
|
||||||
|
value: value.id,
|
||||||
|
});
|
||||||
|
self.ci.nodes.lock(value.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let prev_ret = self.ci.ret.replace(sig.ret);
|
||||||
|
let prev_inline_ret = self.ci.inline_ret.take();
|
||||||
|
self.ci.inline_depth += 1;
|
||||||
|
|
||||||
|
if self.expr(body).is_some() && sig.ret == ty::Id::VOID {
|
||||||
|
self.report(
|
||||||
|
body.pos(),
|
||||||
|
"expected all paths in the fucntion to return \
|
||||||
|
or the return type to be 'void'",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ci.ret = prev_ret;
|
||||||
|
self.ci.inline_depth -= 1;
|
||||||
|
for var in self.ci.scope.vars.drain(arg_base..) {
|
||||||
|
self.ci.nodes.unlock_remove(var.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
core::mem::replace(&mut self.ci.inline_ret, prev_inline_ret).map(|(v, _)| {
|
||||||
|
self.ci.nodes.unlock(v.id);
|
||||||
|
v
|
||||||
|
})
|
||||||
|
}
|
||||||
Expr::Tupl { pos, ty, fields, .. } => {
|
Expr::Tupl { pos, ty, fields, .. } => {
|
||||||
let Some(sty) = ty.map(|ty| self.ty(ty)).or(ctx.ty) else {
|
let Some(sty) = ty.map(|ty| self.ty(ty)).or(ctx.ty) else {
|
||||||
self.report(
|
self.report(
|
||||||
|
@ -2037,6 +2190,7 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
let value = self.expr_ctx(field, Ctx::default().with_ty(ty))?;
|
let value = self.expr_ctx(field, Ctx::default().with_ty(ty))?;
|
||||||
let mem = self.offset(mem, offset);
|
let mem = self.offset(mem, offset);
|
||||||
|
|
||||||
self.store_mem(mem, value.id);
|
self.store_mem(mem, value.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2201,21 +2355,20 @@ impl<'a> Codegen<'a> {
|
||||||
scope: self.ci.scope.clone(),
|
scope: self.ci.scope.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
for (_, var) in &mut self.ci.scope.iter_elems_mut() {
|
for (.., var) in &mut self.ci.scope.iter_elems_mut() {
|
||||||
*var = VOID;
|
*var = VOID;
|
||||||
}
|
}
|
||||||
self.ci.nodes.lock_scope(&self.ci.scope);
|
self.ci.nodes.lock_scope(&self.ci.scope);
|
||||||
|
|
||||||
self.expr(body);
|
self.expr(body);
|
||||||
|
|
||||||
let Loop {
|
let Loop { ctrl: [con, ..], ctrl_scope: [cons, ..], .. } =
|
||||||
node,
|
self.ci.loops.last_mut().unwrap();
|
||||||
ctrl: [mut con, bre],
|
let mut cons = core::mem::take(cons);
|
||||||
ctrl_scope: [mut cons, mut bres],
|
let mut con = *con;
|
||||||
mut scope,
|
|
||||||
} = self.ci.loops.pop().unwrap();
|
|
||||||
|
|
||||||
if con != Nid::MAX {
|
if con != Nid::MAX {
|
||||||
|
self.ci.nodes.unlock(con);
|
||||||
con = self.ci.nodes.new_node(ty::Id::VOID, Kind::Region, [con, self.ci.ctrl]);
|
con = self.ci.nodes.new_node(ty::Id::VOID, Kind::Region, [con, self.ci.ctrl]);
|
||||||
Self::merge_scopes(
|
Self::merge_scopes(
|
||||||
&mut self.ci.nodes,
|
&mut self.ci.nodes,
|
||||||
|
@ -2228,6 +2381,9 @@ impl<'a> Codegen<'a> {
|
||||||
self.ci.ctrl = con;
|
self.ci.ctrl = con;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let Loop { node, ctrl: [.., bre], ctrl_scope: [.., mut bres], mut scope } =
|
||||||
|
self.ci.loops.pop().unwrap();
|
||||||
|
|
||||||
self.ci.nodes.modify_input(node, 1, self.ci.ctrl);
|
self.ci.nodes.modify_input(node, 1, self.ci.ctrl);
|
||||||
|
|
||||||
let idx = self.ci.nodes[node]
|
let idx = self.ci.nodes[node]
|
||||||
|
@ -2243,11 +2399,12 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
self.ci.ctrl = bre;
|
self.ci.ctrl = bre;
|
||||||
|
|
||||||
self.ci.nodes.lock(self.ci.ctrl);
|
|
||||||
|
|
||||||
core::mem::swap(&mut self.ci.scope, &mut bres);
|
core::mem::swap(&mut self.ci.scope, &mut bres);
|
||||||
|
|
||||||
for (((_, dest_value), (_, &mut mut scope_value)), (_, &mut loop_value)) in self
|
debug_assert_eq!(self.ci.scope.vars.len(), scope.vars.len());
|
||||||
|
debug_assert_eq!(self.ci.scope.vars.len(), bres.vars.len());
|
||||||
|
|
||||||
|
for (((.., dest_value), (.., &mut mut scope_value)), (.., &mut loop_value)) in self
|
||||||
.ci
|
.ci
|
||||||
.scope
|
.scope
|
||||||
.iter_elems_mut()
|
.iter_elems_mut()
|
||||||
|
@ -2256,7 +2413,7 @@ impl<'a> Codegen<'a> {
|
||||||
{
|
{
|
||||||
self.ci.nodes.unlock(loop_value);
|
self.ci.nodes.unlock(loop_value);
|
||||||
|
|
||||||
if loop_value != VOID {
|
if self.ci.nodes[scope_value].is_lazy_phi(node) {
|
||||||
self.ci.nodes.unlock(scope_value);
|
self.ci.nodes.unlock(scope_value);
|
||||||
if loop_value != scope_value {
|
if loop_value != scope_value {
|
||||||
scope_value = self.ci.nodes.modify_input(scope_value, 2, loop_value);
|
scope_value = self.ci.nodes.modify_input(scope_value, 2, loop_value);
|
||||||
|
@ -2268,8 +2425,6 @@ impl<'a> Codegen<'a> {
|
||||||
self.ci.nodes.lock(*dest_value);
|
self.ci.nodes.lock(*dest_value);
|
||||||
}
|
}
|
||||||
let phi = &self.ci.nodes[scope_value];
|
let phi = &self.ci.nodes[scope_value];
|
||||||
debug_assert_eq!(phi.kind, Kind::Phi);
|
|
||||||
debug_assert_eq!(phi.inputs[2], VOID);
|
|
||||||
let prev = phi.inputs[1];
|
let prev = phi.inputs[1];
|
||||||
self.ci.nodes.replace(scope_value, prev);
|
self.ci.nodes.replace(scope_value, prev);
|
||||||
scope_value = prev;
|
scope_value = prev;
|
||||||
|
@ -2283,10 +2438,7 @@ impl<'a> Codegen<'a> {
|
||||||
self.ci.nodes.lock(*dest_value);
|
self.ci.nodes.lock(*dest_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_assert!(
|
debug_assert!(!self.ci.nodes[*dest_value].is_lazy_phi(node));
|
||||||
self.ci.nodes[*dest_value].kind != Kind::Phi
|
|
||||||
|| self.ci.nodes[*dest_value].inputs[2] != 0
|
|
||||||
);
|
|
||||||
|
|
||||||
self.ci.nodes.unlock_remove(scope_value);
|
self.ci.nodes.unlock_remove(scope_value);
|
||||||
}
|
}
|
||||||
|
@ -2296,6 +2448,8 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
self.ci.nodes.unlock(self.ci.ctrl);
|
self.ci.nodes.unlock(self.ci.ctrl);
|
||||||
|
|
||||||
|
self.ci.nodes.late_peephole(node);
|
||||||
|
|
||||||
Some(Value::VOID)
|
Some(Value::VOID)
|
||||||
}
|
}
|
||||||
Expr::Break { pos } => self.jump_to(pos, 1),
|
Expr::Break { pos } => self.jump_to(pos, 1),
|
||||||
|
@ -2373,10 +2527,9 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_pattern(&mut self, pat: &Expr, mut right: Value) {
|
fn assign_pattern(&mut self, pat: &Expr, right: Value) {
|
||||||
match *pat {
|
match *pat {
|
||||||
Expr::Ident { id, .. } => {
|
Expr::Ident { id, .. } => {
|
||||||
self.strip_var(&mut right);
|
|
||||||
self.ci.nodes.lock(right.id);
|
self.ci.nodes.lock(right.id);
|
||||||
self.ci.scope.vars.push(Variable {
|
self.ci.scope.vars.push(Variable {
|
||||||
id,
|
id,
|
||||||
|
@ -2426,7 +2579,6 @@ impl<'a> Codegen<'a> {
|
||||||
fn strip_var(&mut self, n: &mut Value) {
|
fn strip_var(&mut self, n: &mut Value) {
|
||||||
if core::mem::take(&mut n.var) {
|
if core::mem::take(&mut n.var) {
|
||||||
let id = (u16::MAX - n.id) as usize;
|
let id = (u16::MAX - n.id) as usize;
|
||||||
self.ci.nodes.load_loop_var(id, &mut self.ci.scope.vars[id].value, &mut self.ci.loops);
|
|
||||||
n.ptr = self.ci.scope.vars[id].ptr;
|
n.ptr = self.ci.scope.vars[id].ptr;
|
||||||
n.id = self.ci.scope.vars[id].value;
|
n.id = self.ci.scope.vars[id].value;
|
||||||
}
|
}
|
||||||
|
@ -2443,6 +2595,7 @@ impl<'a> Codegen<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if loob.ctrl[id] == Nid::MAX {
|
if loob.ctrl[id] == Nid::MAX {
|
||||||
|
self.ci.nodes.lock(self.ci.ctrl);
|
||||||
loob.ctrl[id] = self.ci.ctrl;
|
loob.ctrl[id] = self.ci.ctrl;
|
||||||
loob.ctrl_scope[id] = self.ci.scope.clone();
|
loob.ctrl_scope[id] = self.ci.scope.clone();
|
||||||
loob.ctrl_scope[id].vars.truncate(loob.scope.vars.len());
|
loob.ctrl_scope[id].vars.truncate(loob.scope.vars.len());
|
||||||
|
@ -2463,7 +2616,9 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
loob = self.ci.loops.last_mut().unwrap();
|
loob = self.ci.loops.last_mut().unwrap();
|
||||||
loob.ctrl_scope[id] = scope;
|
loob.ctrl_scope[id] = scope;
|
||||||
|
self.ci.nodes.unlock(loob.ctrl[id]);
|
||||||
loob.ctrl[id] = reg;
|
loob.ctrl[id] = reg;
|
||||||
|
self.ci.nodes.lock(loob.ctrl[id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ci.ctrl = NEVER;
|
self.ci.ctrl = NEVER;
|
||||||
|
@ -2478,7 +2633,7 @@ impl<'a> Codegen<'a> {
|
||||||
from: &mut Scope,
|
from: &mut Scope,
|
||||||
drop_from: bool,
|
drop_from: bool,
|
||||||
) {
|
) {
|
||||||
for (i, ((ty, to_value), (_, from_value))) in
|
for (i, ((.., ty, to_value), (.., from_value))) in
|
||||||
to.iter_elems_mut().zip(from.iter_elems_mut()).enumerate()
|
to.iter_elems_mut().zip(from.iter_elems_mut()).enumerate()
|
||||||
{
|
{
|
||||||
if to_value != from_value {
|
if to_value != from_value {
|
||||||
|
@ -2525,7 +2680,7 @@ impl<'a> Codegen<'a> {
|
||||||
func.offset = u32::MAX - 1;
|
func.offset = u32::MAX - 1;
|
||||||
let sig = func.sig.expect("to emmit only concrete functions");
|
let sig = func.sig.expect("to emmit only concrete functions");
|
||||||
let ast = &self.files[file as usize];
|
let ast = &self.files[file as usize];
|
||||||
let expr = func.expr.get(ast).unwrap();
|
let expr = func.expr.get(ast);
|
||||||
|
|
||||||
self.pool.push_ci(file, Some(sig.ret), 0, &mut self.ci);
|
self.pool.push_ci(file, Some(sig.ret), 0, &mut self.ci);
|
||||||
|
|
||||||
|
@ -2536,11 +2691,16 @@ impl<'a> Codegen<'a> {
|
||||||
let mut sig_args = sig.args.range();
|
let mut sig_args = sig.args.range();
|
||||||
for arg in args.iter() {
|
for arg in args.iter() {
|
||||||
let ty = self.tys.ins.args[sig_args.next().unwrap()];
|
let ty = self.tys.ins.args[sig_args.next().unwrap()];
|
||||||
|
let mut deps = Vc::from([VOID]);
|
||||||
|
if matches!(self.tys.size_of(ty), 9..=16) {
|
||||||
|
deps.push(MEM);
|
||||||
|
}
|
||||||
let value = self.ci.nodes.new_node_nop(ty, Kind::Arg, [VOID]);
|
let value = self.ci.nodes.new_node_nop(ty, Kind::Arg, [VOID]);
|
||||||
self.ci.nodes.lock(value);
|
self.ci.nodes.lock(value);
|
||||||
let sym = parser::find_symbol(&ast.symbols, arg.id);
|
let sym = parser::find_symbol(&ast.symbols, arg.id);
|
||||||
assert!(sym.flags & idfl::COMPTIME == 0, "TODO");
|
assert!(sym.flags & idfl::COMPTIME == 0, "TODO");
|
||||||
self.ci.scope.vars.push(Variable { id: arg.id, value, ty, ptr: false });
|
let ptr = self.tys.size_of(ty) > 8;
|
||||||
|
self.ci.scope.vars.push(Variable { id: arg.id, value, ty, ptr });
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.expr(body).is_some() && sig.ret == ty::Id::VOID {
|
if self.expr(body).is_some() && sig.ret == ty::Id::VOID {
|
||||||
|
@ -2578,12 +2738,6 @@ impl<'a> Codegen<'a> {
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn binop_ty(&mut self, pos: Pos, lhs: &mut Value, rhs: &mut Value, op: TokenKind) -> ty::Id {
|
fn binop_ty(&mut self, pos: Pos, lhs: &mut Value, rhs: &mut Value, op: TokenKind) -> ty::Id {
|
||||||
if let Some(upcasted) = lhs.ty.try_upcast(rhs.ty, ty::TyCheck::BinOp) {
|
if let Some(upcasted) = lhs.ty.try_upcast(rhs.ty, ty::TyCheck::BinOp) {
|
||||||
log::info!(
|
|
||||||
"{} {} {}",
|
|
||||||
self.ty_display(lhs.ty),
|
|
||||||
self.ty_display(rhs.ty),
|
|
||||||
self.ty_display(upcasted)
|
|
||||||
);
|
|
||||||
let to_correct = if lhs.ty != upcasted {
|
let to_correct = if lhs.ty != upcasted {
|
||||||
Some(lhs)
|
Some(lhs)
|
||||||
} else if rhs.ty != upcasted {
|
} else if rhs.ty != upcasted {
|
||||||
|
@ -2643,13 +2797,6 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
|
||||||
fn assert_report(&self, cond: bool, pos: Pos, msg: impl core::fmt::Display) {
|
|
||||||
if !cond {
|
|
||||||
self.report(pos, msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn report(&self, pos: Pos, msg: impl core::fmt::Display) {
|
fn report(&self, pos: Pos, msg: impl core::fmt::Display) {
|
||||||
let mut buf = self.errors.borrow_mut();
|
let mut buf = self.errors.borrow_mut();
|
||||||
|
@ -2755,10 +2902,7 @@ impl<'a> Function<'a> {
|
||||||
regalloc2::Operand::reg_use(self.rg(nid))
|
regalloc2::Operand::reg_use(self.rg(nid))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn def_nid(&mut self, _nid: Nid) {}
|
|
||||||
|
|
||||||
fn drg(&mut self, nid: Nid) -> regalloc2::Operand {
|
fn drg(&mut self, nid: Nid) -> regalloc2::Operand {
|
||||||
self.def_nid(nid);
|
|
||||||
regalloc2::Operand::reg_def(self.rg(nid))
|
regalloc2::Operand::reg_def(self.rg(nid))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2822,6 +2966,9 @@ impl<'a> Function<'a> {
|
||||||
self.add_instr(nid, ops);
|
self.add_instr(nid, ops);
|
||||||
} else {
|
} else {
|
||||||
todo!()
|
todo!()
|
||||||
|
//core::mem::swap(&mut then, &mut else_);
|
||||||
|
//let ops = vec![self.urg(cond)];
|
||||||
|
//self.add_instr(nid, ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.emit_node(then, nid);
|
self.emit_node(then, nid);
|
||||||
|
@ -2839,7 +2986,6 @@ impl<'a> Function<'a> {
|
||||||
if self.nodes[ph].kind != Kind::Phi || self.nodes[ph].ty == ty::Id::VOID {
|
if self.nodes[ph].kind != Kind::Phi || self.nodes[ph].ty == ty::Id::VOID {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
self.def_nid(ph);
|
|
||||||
block.push(self.rg(ph));
|
block.push(self.rg(ph));
|
||||||
}
|
}
|
||||||
self.blocks[self.nodes[nid].ralloc_backref as usize].params = block;
|
self.blocks[self.nodes[nid].ralloc_backref as usize].params = block;
|
||||||
|
@ -2860,7 +3006,7 @@ impl<'a> Function<'a> {
|
||||||
vec![self.urg(self.nodes[node.inputs[1]].inputs[1])]
|
vec![self.urg(self.nodes[node.inputs[1]].inputs[1])]
|
||||||
}
|
}
|
||||||
17.. => {
|
17.. => {
|
||||||
vec![self.urg(node.inputs[1])]
|
vec![self.urg(self.nodes[node.inputs[1]].inputs[1])]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2890,22 +3036,28 @@ impl<'a> Function<'a> {
|
||||||
self.nodes[nid].ralloc_backref = self.add_block(nid);
|
self.nodes[nid].ralloc_backref = self.add_block(nid);
|
||||||
|
|
||||||
let mut parama = self.tys.parama(self.sig.ret);
|
let mut parama = self.tys.parama(self.sig.ret);
|
||||||
for (arg, ti) in
|
for (ti, arg) in
|
||||||
self.nodes[VOID].clone().outputs.into_iter().skip(2).zip(self.sig.args.range())
|
self.sig.args.range().zip(self.nodes[VOID].clone().outputs.into_iter().skip(2))
|
||||||
{
|
{
|
||||||
let ty = self.tys.ins.args[ti];
|
let ty = self.tys.ins.args[ti];
|
||||||
match self.tys.size_of(ty) {
|
match self.tys.size_of(ty) {
|
||||||
0 => continue,
|
0 => continue,
|
||||||
1..=8 => {
|
1..=8 => {
|
||||||
self.def_nid(arg);
|
|
||||||
self.add_instr(NEVER, vec![regalloc2::Operand::reg_fixed_def(
|
self.add_instr(NEVER, vec![regalloc2::Operand::reg_fixed_def(
|
||||||
self.rg(arg),
|
self.rg(arg),
|
||||||
regalloc2::PReg::new(parama.next() as _, regalloc2::RegClass::Int),
|
regalloc2::PReg::new(parama.next() as _, regalloc2::RegClass::Int),
|
||||||
)]);
|
)]);
|
||||||
}
|
}
|
||||||
9..=16 => todo!(),
|
9..=16 => {
|
||||||
|
self.add_instr(NEVER, vec![regalloc2::Operand::reg_fixed_def(
|
||||||
|
self.rg(arg),
|
||||||
|
regalloc2::PReg::new(
|
||||||
|
parama.next_wide() as _,
|
||||||
|
regalloc2::RegClass::Int,
|
||||||
|
),
|
||||||
|
)]);
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.def_nid(arg);
|
|
||||||
self.add_instr(NEVER, vec![regalloc2::Operand::reg_fixed_def(
|
self.add_instr(NEVER, vec![regalloc2::Operand::reg_fixed_def(
|
||||||
self.rg(arg),
|
self.rg(arg),
|
||||||
regalloc2::PReg::new(parama.next() as _, regalloc2::RegClass::Int),
|
regalloc2::PReg::new(parama.next() as _, regalloc2::RegClass::Int),
|
||||||
|
@ -2934,19 +3086,21 @@ impl<'a> Function<'a> {
|
||||||
{
|
{
|
||||||
self.nodes.lock(nid)
|
self.nodes.lock(nid)
|
||||||
}
|
}
|
||||||
Kind::BinOp { op } => {
|
Kind::BinOp { op }
|
||||||
|
if op.cond_op(node.ty.is_signed()).is_some()
|
||||||
|
&& node.outputs.iter().all(|&n| self.nodes[n].kind == Kind::If) =>
|
||||||
|
{
|
||||||
|
self.nodes.lock(nid)
|
||||||
|
}
|
||||||
|
Kind::BinOp { .. } => {
|
||||||
let &[_, lhs, rhs] = node.inputs.as_slice() else { unreachable!() };
|
let &[_, lhs, rhs] = node.inputs.as_slice() else { unreachable!() };
|
||||||
|
|
||||||
let ops = if let Kind::CInt { .. } = self.nodes[rhs].kind
|
let ops = if let Kind::CInt { .. } = self.nodes[rhs].kind
|
||||||
&& self.nodes[rhs].lock_rc != 0
|
&& self.nodes[rhs].lock_rc != 0
|
||||||
{
|
{
|
||||||
vec![self.drg(nid), self.urg(lhs)]
|
vec![self.drg(nid), self.urg(lhs)]
|
||||||
} else if op.binop(node.ty.is_signed(), 8).is_some() {
|
|
||||||
vec![self.drg(nid), self.urg(lhs), self.urg(rhs)]
|
|
||||||
} else if op.cond_op(node.ty.is_signed()).is_some() {
|
|
||||||
return;
|
|
||||||
} else {
|
} else {
|
||||||
todo!("{op}")
|
vec![self.drg(nid), self.urg(lhs), self.urg(rhs)]
|
||||||
};
|
};
|
||||||
self.add_instr(nid, ops);
|
self.add_instr(nid, ops);
|
||||||
}
|
}
|
||||||
|
@ -2960,7 +3114,6 @@ impl<'a> Function<'a> {
|
||||||
|
|
||||||
let fuc = self.tys.ins.funcs[func as usize].sig.unwrap();
|
let fuc = self.tys.ins.funcs[func as usize].sig.unwrap();
|
||||||
if self.tys.size_of(fuc.ret) != 0 {
|
if self.tys.size_of(fuc.ret) != 0 {
|
||||||
self.def_nid(nid);
|
|
||||||
ops.push(regalloc2::Operand::reg_fixed_def(
|
ops.push(regalloc2::Operand::reg_fixed_def(
|
||||||
self.rg(nid),
|
self.rg(nid),
|
||||||
regalloc2::PReg::new(1, regalloc2::RegClass::Int),
|
regalloc2::PReg::new(1, regalloc2::RegClass::Int),
|
||||||
|
@ -2968,18 +3121,39 @@ impl<'a> Function<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut parama = self.tys.parama(fuc.ret);
|
let mut parama = self.tys.parama(fuc.ret);
|
||||||
for (&(mut i), ti) in node.inputs[1..].iter().zip(fuc.args.range()) {
|
let mut inps = node.inputs[1..].iter();
|
||||||
|
for ti in fuc.args.range() {
|
||||||
let ty = self.tys.ins.args[ti];
|
let ty = self.tys.ins.args[ti];
|
||||||
match self.tys.size_of(ty) {
|
match self.tys.size_of(ty) {
|
||||||
0 => continue,
|
0 => continue,
|
||||||
1..=8 => {
|
1..=8 => {
|
||||||
|
ops.push(regalloc2::Operand::reg_fixed_use(
|
||||||
|
self.rg(*inps.next().unwrap()),
|
||||||
|
regalloc2::PReg::new(parama.next() as _, regalloc2::RegClass::Int),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
9..=16 => {
|
||||||
|
let mut i = *inps.next().unwrap();
|
||||||
|
loop {
|
||||||
|
match self.nodes[i].kind {
|
||||||
|
Kind::Stre { .. } => i = self.nodes[i].inputs[2],
|
||||||
|
Kind::Load { .. } => i = self.nodes[i].inputs[1],
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
debug_assert_ne!(i, 0);
|
||||||
|
}
|
||||||
|
debug_assert!(i != 0);
|
||||||
|
ops.push(regalloc2::Operand::reg_fixed_use(
|
||||||
|
self.rg(i),
|
||||||
|
regalloc2::PReg::new(parama.next() as _, regalloc2::RegClass::Int),
|
||||||
|
));
|
||||||
ops.push(regalloc2::Operand::reg_fixed_use(
|
ops.push(regalloc2::Operand::reg_fixed_use(
|
||||||
self.rg(i),
|
self.rg(i),
|
||||||
regalloc2::PReg::new(parama.next() as _, regalloc2::RegClass::Int),
|
regalloc2::PReg::new(parama.next() as _, regalloc2::RegClass::Int),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
9..=16 => todo!("pass in two register"),
|
|
||||||
_ => {
|
_ => {
|
||||||
|
let mut i = *inps.next().unwrap();
|
||||||
loop {
|
loop {
|
||||||
match self.nodes[i].kind {
|
match self.nodes[i].kind {
|
||||||
Kind::Stre { .. } => i = self.nodes[i].inputs[2],
|
Kind::Stre { .. } => i = self.nodes[i].inputs[2],
|
||||||
|
@ -3468,7 +3642,7 @@ mod tests {
|
||||||
c_strings;
|
c_strings;
|
||||||
struct_patterns;
|
struct_patterns;
|
||||||
arrays;
|
arrays;
|
||||||
//inline;
|
inline;
|
||||||
idk;
|
idk;
|
||||||
|
|
||||||
// Incomplete Examples;
|
// Incomplete Examples;
|
||||||
|
@ -3485,7 +3659,7 @@ mod tests {
|
||||||
sort_something_viredly;
|
sort_something_viredly;
|
||||||
//structs_in_registers;
|
//structs_in_registers;
|
||||||
comptime_function_from_another_file;
|
comptime_function_from_another_file;
|
||||||
//inline_test;
|
inline_test;
|
||||||
//inlined_generic_functions;
|
//inlined_generic_functions;
|
||||||
//some_generic_code;
|
//some_generic_code;
|
||||||
//integer_inference_issues;
|
//integer_inference_issues;
|
||||||
|
|
14
lang/tests/son_tests_inline.txt
Normal file
14
lang/tests/son_tests_inline.txt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
main:
|
||||||
|
LI64 r5, 0d
|
||||||
|
LRA r4, r0, :gb
|
||||||
|
LD r6, r4, 0a, 8h
|
||||||
|
LI64 r9, 6d
|
||||||
|
JEQ r6, r5, :0
|
||||||
|
LI64 r12, 1d
|
||||||
|
JMP :1
|
||||||
|
0: CP r12, r9
|
||||||
|
1: SUB64 r1, r12, r9
|
||||||
|
JALA r0, r31, 0a
|
||||||
|
code size: 94
|
||||||
|
ret: 0
|
||||||
|
status: Ok(())
|
92
lang/tests/son_tests_inline_test.txt
Normal file
92
lang/tests/son_tests_inline_test.txt
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
example:
|
||||||
|
ADDI64 r254, r254, -8d
|
||||||
|
ST r31, r254, 0a, 8h
|
||||||
|
LI64 r3, 768d
|
||||||
|
LI64 r2, 0d
|
||||||
|
JAL r31, r0, :integer
|
||||||
|
LD r31, r254, 0a, 8h
|
||||||
|
ADDI64 r254, r254, 8d
|
||||||
|
JALA r0, r31, 0a
|
||||||
|
integer:
|
||||||
|
LI64 r6, 0d
|
||||||
|
LI64 r1, 4d
|
||||||
|
JNE r3, r6, :0
|
||||||
|
SUB64 r10, r3, r2
|
||||||
|
ADDI64 r12, r10, 1d
|
||||||
|
DIRS64 r0, r3, r1, r12
|
||||||
|
ADD64 r1, r3, r2
|
||||||
|
JMP :0
|
||||||
|
0: JALA r0, r31, 0a
|
||||||
|
line:
|
||||||
|
ST r2, r254, 0a, 16h
|
||||||
|
ADDI64 r2, r254, 0d
|
||||||
|
ST r4, r254, 0a, 16h
|
||||||
|
ADDI64 r4, r254, 0d
|
||||||
|
ST r6, r254, 0a, 16h
|
||||||
|
ADDI64 r6, r254, 0d
|
||||||
|
LD r9, r4, 0a, 8h
|
||||||
|
LD r11, r2, 0a, 8h
|
||||||
|
JGTU r11, r9, :0
|
||||||
|
JMP :0
|
||||||
|
0: JALA r0, r31, 0a
|
||||||
|
main:
|
||||||
|
ADDI64 r254, r254, -112d
|
||||||
|
ST r31, r254, 96a, 16h
|
||||||
|
LI64 r32, 10d
|
||||||
|
LI64 r1, 0d
|
||||||
|
ADDI64 r7, r254, 48d
|
||||||
|
ADDI64 r5, r254, 64d
|
||||||
|
ADDI64 r3, r254, 80d
|
||||||
|
ST r1, r254, 80a, 8h
|
||||||
|
ST r1, r254, 88a, 8h
|
||||||
|
ST r1, r254, 64a, 8h
|
||||||
|
ST r1, r254, 72a, 8h
|
||||||
|
ST r1, r254, 48a, 8h
|
||||||
|
ST r1, r254, 56a, 8h
|
||||||
|
CP r8, r32
|
||||||
|
CP r2, r3
|
||||||
|
CP r4, r5
|
||||||
|
CP r6, r7
|
||||||
|
JAL r31, r0, :line
|
||||||
|
ADDI64 r7, r254, 0d
|
||||||
|
ADDI64 r5, r254, 16d
|
||||||
|
ADDI64 r3, r254, 32d
|
||||||
|
ST r1, r254, 32a, 8h
|
||||||
|
ST r1, r254, 40a, 8h
|
||||||
|
ST r1, r254, 16a, 8h
|
||||||
|
ST r1, r254, 24a, 8h
|
||||||
|
ST r1, r254, 0a, 8h
|
||||||
|
ST r1, r254, 8a, 8h
|
||||||
|
CP r8, r32
|
||||||
|
CP r2, r3
|
||||||
|
CP r4, r5
|
||||||
|
CP r6, r7
|
||||||
|
JAL r31, r0, :rect_line
|
||||||
|
JAL r31, r0, :example
|
||||||
|
LD r31, r254, 96a, 16h
|
||||||
|
ADDI64 r254, r254, 112d
|
||||||
|
JALA r0, r31, 0a
|
||||||
|
rect_line:
|
||||||
|
ST r2, r254, 0a, 16h
|
||||||
|
ADDI64 r2, r254, 0d
|
||||||
|
ST r4, r254, 0a, 16h
|
||||||
|
ADDI64 r4, r254, 0d
|
||||||
|
ST r6, r254, 0a, 16h
|
||||||
|
ADDI64 r6, r254, 0d
|
||||||
|
LI64 r10, 0d
|
||||||
|
LD r12, r2, 8a, 8h
|
||||||
|
LD r4, r4, 0a, 8h
|
||||||
|
ADD64 r6, r4, r12
|
||||||
|
3: JNE r10, r8, :0
|
||||||
|
JMP :1
|
||||||
|
0: CP r9, r12
|
||||||
|
4: JNE r6, r9, :2
|
||||||
|
ADDI64 r10, r10, 1d
|
||||||
|
JMP :3
|
||||||
|
2: ADDI64 r9, r9, 1d
|
||||||
|
JMP :4
|
||||||
|
1: JALA r0, r31, 0a
|
||||||
|
timed out
|
||||||
|
code size: 797
|
||||||
|
ret: 0
|
||||||
|
status: Ok(())
|
Loading…
Reference in a new issue