fixing struct return and copy miscompilation

This commit is contained in:
Jakub Doka 2024-10-20 18:49:41 +02:00
parent 3aff6fc006
commit 1da900461c
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
8 changed files with 165 additions and 68 deletions

View file

@ -634,7 +634,7 @@ Foo := struct {x: int, y: u32, z: u32}
#### sort_something_viredly #### sort_something_viredly
```hb ```hb
main := fn(): int { main := fn(): int {
return sqrt(1) return sqrt(100)
} }
sqrt := fn(x: int): int { sqrt := fn(x: int): int {

View file

@ -1159,10 +1159,6 @@ impl Codegen {
E::String { pos, literal } => { E::String { pos, literal } => {
let literal = &literal[1..literal.len() - 1]; let literal = &literal[1..literal.len() - 1];
if !literal.ends_with("\\0") {
self.report(pos, "string literal must end with null byte (for now)");
}
let report = |bytes: &core::str::Bytes, message: &str| { let report = |bytes: &core::str::Bytes, message: &str| {
self.report(pos + (literal.len() - bytes.len()) as u32 - 1, message) self.report(pos + (literal.len() - bytes.len()) as u32 - 1, message)
}; };

View file

@ -1762,6 +1762,10 @@ fn endoce_string(
str.push(b); str.push(b);
} }
if str.last() != Some(&0) {
report(&bytes, "string literal must end with null byte (for now)");
}
Some(()) Some(())
} }

View file

@ -140,7 +140,7 @@ impl Nodes {
Node { ralloc_backref: u16::MAX, inputs: inps.into(), kind, ty, ..Default::default() }; Node { ralloc_backref: u16::MAX, inputs: inps.into(), kind, ty, ..Default::default() };
let mut lookup_meta = None; let mut lookup_meta = None;
if !node.is_gvnd() { if !node.is_not_gvnd() {
let (raw_entry, hash) = self.lookup.entry(node.key(), &self.values); let (raw_entry, hash) = self.lookup.entry(node.key(), &self.values);
let entry = match raw_entry { let entry = match raw_entry {
@ -170,7 +170,7 @@ impl Nodes {
} }
fn remove_node_lookup(&mut self, target: Nid) { fn remove_node_lookup(&mut self, target: Nid) {
if !self[target].is_gvnd() { if !self[target].is_not_gvnd() {
self.lookup.remove(&target, &self.values).unwrap(); self.lookup.remove(&target, &self.values).unwrap();
} }
} }
@ -482,6 +482,7 @@ impl Nodes {
Kind::Load => write!(out, "load: "), Kind::Load => write!(out, "load: "),
Kind::Stre => write!(out, "stre: "), Kind::Stre => write!(out, "stre: "),
Kind::Mem => write!(out, " mem: "), Kind::Mem => write!(out, " mem: "),
Kind::Idk => write!(out, " idk: "),
}?; }?;
if self[node].kind != Kind::Loop && self[node].kind != Kind::Region { if self[node].kind != Kind::Loop && self[node].kind != Kind::Region {
@ -774,9 +775,7 @@ impl Nodes {
} }
fn lock_scope(&mut self, scope: &Scope) { fn lock_scope(&mut self, scope: &Scope) {
if let Some(str) = scope.store.to_store() { self.lock(scope.store);
self.lock(str);
}
for &load in &scope.loads { for &load in &scope.loads {
self.lock(load); self.lock(load);
} }
@ -786,9 +785,7 @@ impl Nodes {
} }
fn unlock_remove_scope(&mut self, scope: &Scope) { fn unlock_remove_scope(&mut self, scope: &Scope) {
if let Some(str) = scope.store.to_store() { self.unlock_remove(scope.store);
self.unlock_remove(str);
}
for &load in &scope.loads { for &load in &scope.loads {
self.unlock_remove(load); self.unlock_remove(load);
} }
@ -856,6 +853,8 @@ pub enum Kind {
func: ty::Func, func: ty::Func,
}, },
// [ctrl] // [ctrl]
Idk,
// [ctrl]
Stck, Stck,
// [ctrl, memory] // [ctrl, memory]
Load, Load,
@ -930,8 +929,8 @@ impl Node {
self.kind == Kind::Phi && self.inputs[2] == 0 self.kind == Kind::Phi && self.inputs[2] == 0
} }
fn is_gvnd(&self) -> bool { fn is_not_gvnd(&self) -> bool {
self.is_lazy_phi() || matches!(self.kind, Kind::Arg) self.is_lazy_phi() || matches!(self.kind, Kind::Arg | Kind::Stck)
} }
} }
@ -1019,7 +1018,6 @@ impl ItemCtx {
} }
fn finalize(&mut self) { fn finalize(&mut self) {
self.nodes.unlock(ENTRY);
self.nodes.unlock(NEVER); self.nodes.unlock(NEVER);
self.nodes.unlock_remove_scope(&core::mem::take(&mut self.scope)); self.nodes.unlock_remove_scope(&core::mem::take(&mut self.scope));
self.nodes.unlock(MEM); self.nodes.unlock(MEM);
@ -1109,6 +1107,14 @@ impl ItemCtx {
} }
} }
Kind::Return => { Kind::Return => {
match tys.size_of(sig.ret) {
0..=8 => {}
9..=16 => todo!(),
size @ 17.. => {
self.emit(instrs::bmc(atr(allocs[0]), 1, size.try_into().unwrap()));
}
}
if i != func.blocks.len() - 1 { if i != func.blocks.len() - 1 {
let rel = Reloc::new(self.code.len(), 1, 4); let rel = Reloc::new(self.code.len(), 1, 4);
self.ret_relocs.push(rel); self.ret_relocs.push(rel);
@ -1163,6 +1169,7 @@ impl ItemCtx {
let offset = func.nodes[nid].offset; let offset = func.nodes[nid].offset;
self.emit(instrs::addi64(atr(allocs[0]), base, offset as _)); self.emit(instrs::addi64(atr(allocs[0]), base, offset as _));
} }
Kind::Idk => {}
Kind::Load => { Kind::Load => {
let mut region = node.inputs[1]; let mut region = node.inputs[1];
let mut offset = 0; let mut offset = 0;
@ -1186,21 +1193,24 @@ impl ItemCtx {
Kind::Stre => { Kind::Stre => {
let mut region = node.inputs[2]; let mut region = node.inputs[2];
let mut offset = 0; let mut offset = 0;
let size = u16::try_from(tys.size_of(node.ty)).expect("TODO");
if func.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add }) if func.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add })
&& let Kind::CInt { value } = && let Kind::CInt { value } =
func.nodes[func.nodes[region].inputs[2]].kind func.nodes[func.nodes[region].inputs[2]].kind
&& size <= 8
{ {
region = func.nodes[region].inputs[1]; region = func.nodes[region].inputs[1];
offset = value as Offset; offset = value as Offset;
} }
let size = u16::try_from(tys.size_of(node.ty)).expect("TODO");
let nd = &func.nodes[region]; let nd = &func.nodes[region];
let (base, offset, src) = match nd.kind { let (base, offset, src) = match nd.kind {
Kind::Stck => (reg::STACK_PTR, nd.offset + offset, allocs[0]), Kind::Stck if size <= 8 => {
(reg::STACK_PTR, nd.offset + offset, allocs[0])
}
_ => (atr(allocs[0]), offset, allocs[1]), _ => (atr(allocs[0]), offset, allocs[1]),
}; };
if size > 8 { if size > 8 {
self.emit(instrs::bmc(base, atr(src), size)); self.emit(instrs::bmc(atr(src), base, size));
} else { } else {
self.emit(instrs::st(atr(src), base, offset as _, size)); self.emit(instrs::st(atr(src), base, offset as _, size));
} }
@ -1539,8 +1549,8 @@ impl<'a> Codegen<'a> {
let mut vc = Vc::from([VOID, value, region]); let mut vc = Vc::from([VOID, value, region]);
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);
self.ci.nodes.unlock(self.ci.scope.store);
if let Some(str) = self.ci.scope.store.to_store() { if let Some(str) = self.ci.scope.store.to_store() {
self.ci.nodes.unlock(str);
vc.push(str); vc.push(str);
} }
for load in self.ci.scope.loads.drain(..) { for load in self.ci.scope.loads.drain(..) {
@ -1592,6 +1602,23 @@ impl<'a> Codegen<'a> {
fn raw_expr_ctx(&mut self, expr: &Expr, ctx: Ctx) -> Option<Value> { fn raw_expr_ctx(&mut self, expr: &Expr, ctx: Ctx) -> Option<Value> {
// ordered by complexity of the expression // ordered by complexity of the expression
match *expr { match *expr {
Expr::Idk { pos } => {
let Some(ty) = ctx.ty else {
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(_)) {
let stck = self.ci.nodes.new_node(ty, Kind::Stck, [VOID, MEM]);
Some(Value::ptr(stck).ty(ty))
} else {
Some(self.ci.nodes.new_node_lit(ty, Kind::Idk, [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() || ty.is_pointer()).unwrap_or(ty::Id::INT), ctx.ty.filter(|ty| ty.is_integer() || ty.is_pointer()).unwrap_or(ty::Id::INT),
Kind::CInt { value }, Kind::CInt { value },
@ -1620,10 +1647,6 @@ impl<'a> Codegen<'a> {
Expr::String { pos, literal } => { Expr::String { pos, literal } => {
let literal = &literal[1..literal.len() - 1]; let literal = &literal[1..literal.len() - 1];
if !literal.ends_with("\\0") {
self.report(pos, "string literal must end with null byte (for now)");
}
let report = |bytes: &core::str::Bytes, message: &str| { let report = |bytes: &core::str::Bytes, message: &str| {
self.report(pos + (literal.len() - bytes.len()) as u32 - 1, message) self.report(pos + (literal.len() - bytes.len()) as u32 - 1, message)
}; };
@ -1696,7 +1719,7 @@ impl<'a> Codegen<'a> {
return Value::NEVER; return Value::NEVER;
}; };
Some(Value::ptr(self.offset(vtarget.id, ty, offset)).ty(ty)) Some(Value::ptr(self.offset(vtarget.id, offset)).ty(ty))
} }
Expr::UnOp { op: TokenKind::Band, val, .. } => { Expr::UnOp { op: TokenKind::Band, val, .. } => {
let ctx = Ctx { ty: ctx.ty.and_then(|ty| self.tys.base_of(ty)) }; let ctx = Ctx { ty: ctx.ty.and_then(|ty| self.tys.base_of(ty)) };
@ -1751,9 +1774,9 @@ impl<'a> Codegen<'a> {
} }
Expr::BinOp { left, op: TokenKind::Assign, right } => { Expr::BinOp { left, op: TokenKind::Assign, right } => {
let dest = self.raw_expr(left)?; let dest = self.raw_expr(left)?;
let value = self.expr(right)?; let value = self.expr_ctx(right, Ctx::default().with_ty(dest.ty))?;
self.assert_ty(left.pos(), value.ty, dest.ty, "assignment dest"); self.assert_ty(left.pos(), value.ty, dest.ty, "assignment source");
if dest.var { if dest.var {
self.ci.nodes.lock(value.id); self.ci.nodes.lock(value.id);
@ -1805,7 +1828,8 @@ impl<'a> Codegen<'a> {
let offset = let offset =
self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Mul }, inps); self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Mul }, inps);
let inps = [VOID, bs.id, offset]; let inps = [VOID, bs.id, offset];
let ptr = self.ci.nodes.new_node(elem, Kind::BinOp { op: TokenKind::Add }, inps); let ptr =
self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Add }, inps);
Some(Value::ptr(ptr).ty(elem)) Some(Value::ptr(ptr).ty(elem))
} }
Expr::Directive { name: "sizeof", args: [ty], .. } => { Expr::Directive { name: "sizeof", args: [ty], .. } => {
@ -1857,7 +1881,7 @@ impl<'a> Codegen<'a> {
} }
Expr::Directive { name: "as", args: [ty, expr], .. } => { Expr::Directive { name: "as", args: [ty, expr], .. } => {
let ctx = Ctx::default().with_ty(self.ty(ty)); let ctx = Ctx::default().with_ty(self.ty(ty));
self.expr_ctx(expr, ctx) self.raw_expr_ctx(expr, ctx)
} }
Expr::Call { func, args, .. } => { Expr::Call { func, args, .. } => {
self.ci.call_count += 1; self.ci.call_count += 1;
@ -1918,11 +1942,22 @@ impl<'a> Codegen<'a> {
false false
}); });
let alt_value = match self.tys.size_of(sig.ret) {
0..=8 => None,
9..=16 => todo!(),
17.. => {
let stck = self.ci.nodes.new_node_nop(sig.ret, Kind::Stck, [VOID, MEM]);
inps.push(stck);
Some(Value::ptr(stck).ty(sig.ret))
}
};
self.ci.ctrl = self.ci.nodes.new_node(sig.ret, Kind::Call { func: fnc }, inps); self.ci.ctrl = self.ci.nodes.new_node(sig.ret, Kind::Call { func: fnc }, inps);
self.store_mem(VOID, VOID); self.store_mem(VOID, VOID);
Some(Value::new(self.ci.ctrl).ty(sig.ret)) alt_value.or(Some(Value::new(self.ci.ctrl).ty(sig.ret)))
} }
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 {
@ -1948,7 +1983,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, ty, offset); let mem = self.offset(mem, offset);
self.store_mem(mem, value.id); self.store_mem(mem, value.id);
} }
@ -1995,7 +2030,7 @@ impl<'a> Codegen<'a> {
{ {
let value = self.expr_ctx(field, Ctx::default().with_ty(elem))?; let value = self.expr_ctx(field, Ctx::default().with_ty(elem))?;
_ = self.assert_ty(field.pos(), value.ty, elem, "array value"); _ = self.assert_ty(field.pos(), value.ty, elem, "array value");
let mem = self.offset(mem, elem, offset); let mem = self.offset(mem, offset);
self.store_mem(mem, value.id); self.store_mem(mem, value.id);
} }
@ -2063,7 +2098,7 @@ impl<'a> Codegen<'a> {
} }
let value = self.expr_ctx(&field.value, Ctx::default().with_ty(ty))?; let value = self.expr_ctx(&field.value, Ctx::default().with_ty(ty))?;
let mem = self.offset(mem, ty, offset); let mem = self.offset(mem, offset);
self.store_mem(mem, value.id); self.store_mem(mem, value.id);
} }
@ -2238,9 +2273,7 @@ impl<'a> Codegen<'a> {
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);
let orig_store = self.ci.scope.store; let orig_store = self.ci.scope.store;
if let Some(str) = orig_store.to_store() { self.ci.nodes.lock(orig_store);
self.ci.nodes.lock(str);
}
let else_scope = self.ci.scope.clone(); let else_scope = self.ci.scope.clone();
self.ci.nodes.lock_scope(&else_scope); self.ci.nodes.lock_scope(&else_scope);
@ -2255,9 +2288,7 @@ impl<'a> Codegen<'a> {
self.ci.ctrl self.ci.ctrl
}; };
if let Some(str) = orig_store.to_store() { self.ci.nodes.unlock_remove(orig_store);
self.ci.nodes.unlock_remove(str);
}
if lcntrl == Nid::MAX && rcntrl == Nid::MAX { if lcntrl == Nid::MAX && rcntrl == Nid::MAX {
self.ci.nodes.unlock_remove_scope(&then_scope); self.ci.nodes.unlock_remove_scope(&then_scope);
@ -2298,14 +2329,14 @@ impl<'a> Codegen<'a> {
Some(n) Some(n)
} }
fn offset(&mut self, val: Nid, ty: ty::Id, off: Offset) -> Nid { fn offset(&mut self, val: Nid, off: Offset) -> Nid {
if off == 0 { if off == 0 {
return val; return val;
} }
let off = self.ci.nodes.new_node_nop(ty::Id::INT, Kind::CInt { value: off as i64 }, [VOID]); let off = self.ci.nodes.new_node_nop(ty::Id::INT, Kind::CInt { value: off as i64 }, [VOID]);
let inps = [VOID, val, off]; let inps = [VOID, val, off];
self.ci.nodes.new_node(ty, Kind::BinOp { op: TokenKind::Add }, inps) self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Add }, inps)
} }
fn strip_var(&mut self, n: &mut Value) { fn strip_var(&mut self, n: &mut Value) {
@ -2688,14 +2719,20 @@ impl<'a> Function<'a> {
} }
} }
Kind::Return => { Kind::Return => {
let ops = if node.inputs[1] != VOID { let ops = match self.tys.size_of(self.sig.ret) {
0 => vec![],
1..=8 => {
vec![regalloc2::Operand::reg_fixed_use( vec![regalloc2::Operand::reg_fixed_use(
self.rg(node.inputs[1]), self.rg(node.inputs[1]),
regalloc2::PReg::new(1, regalloc2::RegClass::Int), regalloc2::PReg::new(1, regalloc2::RegClass::Int),
)] )]
} else { }
vec![] 9..=16 => todo!(),
17.. => {
vec![self.urg(node.inputs[1])]
}
}; };
self.add_instr(nid, ops); self.add_instr(nid, ops);
self.emit_node(node.outputs[0], nid); self.emit_node(node.outputs[0], nid);
} }
@ -2755,10 +2792,10 @@ impl<'a> Function<'a> {
} }
Kind::BinOp { op: TokenKind::Add } Kind::BinOp { op: TokenKind::Add }
if self.nodes.is_const(node.inputs[2]) if self.nodes.is_const(node.inputs[2])
&& node && node.outputs.iter().all(|&n| {
.outputs matches!(self.nodes[n].kind, Kind::Stre | Kind::Load)
.iter() && self.tys.size_of(self.nodes[n].ty) <= 8
.all(|&n| matches!(self.nodes[n].kind, Kind::Stre | Kind::Load)) => }) =>
{ {
self.nodes.lock(nid) self.nodes.lock(nid)
} }
@ -2825,6 +2862,17 @@ impl<'a> Function<'a> {
} }
} }
match self.tys.size_of(fuc.ret) {
0..=8 => {}
9..=16 => todo!(),
17.. => {
ops.push(regalloc2::Operand::reg_fixed_use(
self.rg(*node.inputs.last().unwrap()),
regalloc2::PReg::new(1, regalloc2::RegClass::Int),
));
}
}
self.add_instr(nid, ops); self.add_instr(nid, ops);
for o in node.outputs.into_iter().rev() { for o in node.outputs.into_iter().rev() {
@ -2851,6 +2899,10 @@ impl<'a> Function<'a> {
let ops = vec![self.drg(nid)]; let ops = vec![self.drg(nid)];
self.add_instr(nid, ops); self.add_instr(nid, ops);
} }
Kind::Idk => {
let ops = vec![self.drg(nid)];
self.add_instr(nid, ops);
}
Kind::Phi | Kind::Arg | Kind::Mem => {} Kind::Phi | Kind::Arg | Kind::Mem => {}
Kind::Load { .. } => { Kind::Load { .. } => {
let mut region = node.inputs[1]; let mut region = node.inputs[1];
@ -3283,7 +3335,7 @@ mod tests {
//struct_patterns; //struct_patterns;
arrays; arrays;
//inline; //inline;
//idk; idk;
//wide_ret; //wide_ret;
// Incomplete Examples; // Incomplete Examples;

View file

@ -1,11 +1,36 @@
main: main:
ADDI64 r254, r254, -16d ADDI64 r254, r254, -8d
ST r31, r254, 0a, 16h ST r31, r254, 0a, 8h
LI64 r32, 1610612737d LI64 r2, 1d
LI64 r1, 0d JAL r31, r0, :sqrt
LD r31, r254, 0a, 16h LD r31, r254, 0a, 8h
ADDI64 r254, r254, 16d ADDI64 r254, r254, 8d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 87 sqrt:
ret: 0 ADDI64 r254, r254, -56d
ST r31, r254, 0a, 56h
CP r32, r2
LI64 r33, 0d
LI64 r34, 0d
LI64 r35, 32768d
LI64 r36, 15d
3: LI64 r37, 0d
JNE r35, r37, :0
JMP :1
0: ADDI64 r36, r36, -1d
CP r37, r34
SLUI64 r37, r37, 1b
ADD64 r33, r35, r37
SLU64 r33, r33, r36
JLTS r32, r33, :2
ADD64 r34, r34, r35
SUB64 r32, r32, r33
2: SRUI64 r35, r35, 1b
JMP :3
1: CP r1, r34
LD r31, r254, 0a, 56h
ADDI64 r254, r254, 56d
JALA r0, r31, 0a
code size: 257
ret: 1
status: Ok(()) status: Ok(())

View file

@ -14,12 +14,13 @@ main:
ADDI64 r254, r254, 8d ADDI64 r254, r254, 8d
JALA r0, r31, 0a JALA r0, r31, 0a
outl: outl:
ADDI64 r254, r254, -16d ADDI64 r254, r254, -24d
ST r31, r254, 0a, 16h ST r31, r254, 0a, 24h
LRA r32, r0, :"whahaha\0" LRA r32, r0, :"whahaha\0"
LD r31, r254, 0a, 16h LI64 r33, 0d
ADDI64 r254, r254, 16d LD r31, r254, 0a, 24h
ADDI64 r254, r254, 24d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 229 code size: 239
ret: 0 ret: 0
status: Ok(()) status: Ok(())

View file

@ -0,0 +1,19 @@
main:
ADDI64 r254, r254, -128d
LI64 r6, 69d
LI64 r5, 128d
LI64 r7, 0d
ADDI64 r4, r254, 0d
2: JLTU r7, r5, :0
LD r1, r254, 42a, 1h
JMP :1
0: ADDI64 r3, r7, 1d
ADD64 r2, r7, r4
ST r6, r2, 0a, 1h
CP r7, r3
JMP :2
1: ADDI64 r254, r254, 128d
JALA r0, r31, 0a
code size: 141
ret: 69
status: Ok(())

View file

@ -1,7 +1,7 @@
main: main:
ADDI64 r254, r254, -8d ADDI64 r254, r254, -8d
ST r31, r254, 0a, 8h ST r31, r254, 0a, 8h
LI64 r2, 1d LI64 r2, 100d
JAL r31, r0, :sqrt JAL r31, r0, :sqrt
LD r31, r254, 0a, 8h LD r31, r254, 0a, 8h
ADDI64 r254, r254, 8d ADDI64 r254, r254, 8d
@ -25,5 +25,5 @@ sqrt:
JMP :3 JMP :3
1: JALA r0, r31, 0a 1: JALA r0, r31, 0a
code size: 188 code size: 188
ret: 0 ret: 14
status: Ok(()) status: Ok(())