forked from AbleOS/holey-bytes
fixing struct return and copy miscompilation
This commit is contained in:
parent
3aff6fc006
commit
1da900461c
|
@ -634,7 +634,7 @@ Foo := struct {x: int, y: u32, z: u32}
|
|||
#### sort_something_viredly
|
||||
```hb
|
||||
main := fn(): int {
|
||||
return sqrt(1)
|
||||
return sqrt(100)
|
||||
}
|
||||
|
||||
sqrt := fn(x: int): int {
|
||||
|
|
|
@ -1159,10 +1159,6 @@ impl Codegen {
|
|||
E::String { pos, literal } => {
|
||||
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| {
|
||||
self.report(pos + (literal.len() - bytes.len()) as u32 - 1, message)
|
||||
};
|
||||
|
|
|
@ -1762,6 +1762,10 @@ fn endoce_string(
|
|||
str.push(b);
|
||||
}
|
||||
|
||||
if str.last() != Some(&0) {
|
||||
report(&bytes, "string literal must end with null byte (for now)");
|
||||
}
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
|
|
140
lang/src/son.rs
140
lang/src/son.rs
|
@ -140,7 +140,7 @@ impl Nodes {
|
|||
Node { ralloc_backref: u16::MAX, inputs: inps.into(), kind, ty, ..Default::default() };
|
||||
|
||||
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 entry = match raw_entry {
|
||||
|
@ -170,7 +170,7 @@ impl Nodes {
|
|||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -482,6 +482,7 @@ impl Nodes {
|
|||
Kind::Load => write!(out, "load: "),
|
||||
Kind::Stre => write!(out, "stre: "),
|
||||
Kind::Mem => write!(out, " mem: "),
|
||||
Kind::Idk => write!(out, " idk: "),
|
||||
}?;
|
||||
|
||||
if self[node].kind != Kind::Loop && self[node].kind != Kind::Region {
|
||||
|
@ -774,9 +775,7 @@ impl Nodes {
|
|||
}
|
||||
|
||||
fn lock_scope(&mut self, scope: &Scope) {
|
||||
if let Some(str) = scope.store.to_store() {
|
||||
self.lock(str);
|
||||
}
|
||||
self.lock(scope.store);
|
||||
for &load in &scope.loads {
|
||||
self.lock(load);
|
||||
}
|
||||
|
@ -786,9 +785,7 @@ impl Nodes {
|
|||
}
|
||||
|
||||
fn unlock_remove_scope(&mut self, scope: &Scope) {
|
||||
if let Some(str) = scope.store.to_store() {
|
||||
self.unlock_remove(str);
|
||||
}
|
||||
self.unlock_remove(scope.store);
|
||||
for &load in &scope.loads {
|
||||
self.unlock_remove(load);
|
||||
}
|
||||
|
@ -856,6 +853,8 @@ pub enum Kind {
|
|||
func: ty::Func,
|
||||
},
|
||||
// [ctrl]
|
||||
Idk,
|
||||
// [ctrl]
|
||||
Stck,
|
||||
// [ctrl, memory]
|
||||
Load,
|
||||
|
@ -930,8 +929,8 @@ impl Node {
|
|||
self.kind == Kind::Phi && self.inputs[2] == 0
|
||||
}
|
||||
|
||||
fn is_gvnd(&self) -> bool {
|
||||
self.is_lazy_phi() || matches!(self.kind, Kind::Arg)
|
||||
fn is_not_gvnd(&self) -> bool {
|
||||
self.is_lazy_phi() || matches!(self.kind, Kind::Arg | Kind::Stck)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1019,7 +1018,6 @@ impl ItemCtx {
|
|||
}
|
||||
|
||||
fn finalize(&mut self) {
|
||||
self.nodes.unlock(ENTRY);
|
||||
self.nodes.unlock(NEVER);
|
||||
self.nodes.unlock_remove_scope(&core::mem::take(&mut self.scope));
|
||||
self.nodes.unlock(MEM);
|
||||
|
@ -1109,6 +1107,14 @@ impl ItemCtx {
|
|||
}
|
||||
}
|
||||
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 {
|
||||
let rel = Reloc::new(self.code.len(), 1, 4);
|
||||
self.ret_relocs.push(rel);
|
||||
|
@ -1163,6 +1169,7 @@ impl ItemCtx {
|
|||
let offset = func.nodes[nid].offset;
|
||||
self.emit(instrs::addi64(atr(allocs[0]), base, offset as _));
|
||||
}
|
||||
Kind::Idk => {}
|
||||
Kind::Load => {
|
||||
let mut region = node.inputs[1];
|
||||
let mut offset = 0;
|
||||
|
@ -1186,21 +1193,24 @@ impl ItemCtx {
|
|||
Kind::Stre => {
|
||||
let mut region = node.inputs[2];
|
||||
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 })
|
||||
&& let Kind::CInt { value } =
|
||||
func.nodes[func.nodes[region].inputs[2]].kind
|
||||
&& size <= 8
|
||||
{
|
||||
region = func.nodes[region].inputs[1];
|
||||
offset = value as Offset;
|
||||
}
|
||||
let size = u16::try_from(tys.size_of(node.ty)).expect("TODO");
|
||||
let nd = &func.nodes[region];
|
||||
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]),
|
||||
};
|
||||
if size > 8 {
|
||||
self.emit(instrs::bmc(base, atr(src), size));
|
||||
self.emit(instrs::bmc(atr(src), base, size));
|
||||
} else {
|
||||
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]);
|
||||
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() {
|
||||
self.ci.nodes.unlock(str);
|
||||
vc.push(str);
|
||||
}
|
||||
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> {
|
||||
// ordered by complexity of the expression
|
||||
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(
|
||||
ctx.ty.filter(|ty| ty.is_integer() || ty.is_pointer()).unwrap_or(ty::Id::INT),
|
||||
Kind::CInt { value },
|
||||
|
@ -1620,10 +1647,6 @@ impl<'a> Codegen<'a> {
|
|||
Expr::String { pos, literal } => {
|
||||
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| {
|
||||
self.report(pos + (literal.len() - bytes.len()) as u32 - 1, message)
|
||||
};
|
||||
|
@ -1696,7 +1719,7 @@ impl<'a> Codegen<'a> {
|
|||
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, .. } => {
|
||||
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 } => {
|
||||
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 {
|
||||
self.ci.nodes.lock(value.id);
|
||||
|
@ -1805,7 +1828,8 @@ impl<'a> Codegen<'a> {
|
|||
let offset =
|
||||
self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Mul }, inps);
|
||||
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))
|
||||
}
|
||||
Expr::Directive { name: "sizeof", args: [ty], .. } => {
|
||||
|
@ -1857,7 +1881,7 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
Expr::Directive { name: "as", args: [ty, expr], .. } => {
|
||||
let ctx = Ctx::default().with_ty(self.ty(ty));
|
||||
self.expr_ctx(expr, ctx)
|
||||
self.raw_expr_ctx(expr, ctx)
|
||||
}
|
||||
Expr::Call { func, args, .. } => {
|
||||
self.ci.call_count += 1;
|
||||
|
@ -1918,11 +1942,22 @@ impl<'a> Codegen<'a> {
|
|||
|
||||
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.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, .. } => {
|
||||
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 mem = self.offset(mem, ty, offset);
|
||||
let mem = self.offset(mem, offset);
|
||||
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))?;
|
||||
_ = 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);
|
||||
}
|
||||
|
||||
|
@ -2063,7 +2098,7 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -2238,9 +2273,7 @@ impl<'a> Codegen<'a> {
|
|||
|
||||
self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops);
|
||||
let orig_store = self.ci.scope.store;
|
||||
if let Some(str) = orig_store.to_store() {
|
||||
self.ci.nodes.lock(str);
|
||||
}
|
||||
self.ci.nodes.lock(orig_store);
|
||||
let else_scope = self.ci.scope.clone();
|
||||
self.ci.nodes.lock_scope(&else_scope);
|
||||
|
||||
|
@ -2255,9 +2288,7 @@ impl<'a> Codegen<'a> {
|
|||
self.ci.ctrl
|
||||
};
|
||||
|
||||
if let Some(str) = orig_store.to_store() {
|
||||
self.ci.nodes.unlock_remove(str);
|
||||
}
|
||||
self.ci.nodes.unlock_remove(orig_store);
|
||||
|
||||
if lcntrl == Nid::MAX && rcntrl == Nid::MAX {
|
||||
self.ci.nodes.unlock_remove_scope(&then_scope);
|
||||
|
@ -2298,14 +2329,14 @@ impl<'a> Codegen<'a> {
|
|||
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 {
|
||||
return val;
|
||||
}
|
||||
|
||||
let off = self.ci.nodes.new_node_nop(ty::Id::INT, Kind::CInt { value: off as i64 }, [VOID]);
|
||||
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) {
|
||||
|
@ -2688,14 +2719,20 @@ impl<'a> Function<'a> {
|
|||
}
|
||||
}
|
||||
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(
|
||||
self.rg(node.inputs[1]),
|
||||
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.emit_node(node.outputs[0], nid);
|
||||
}
|
||||
|
@ -2755,10 +2792,10 @@ impl<'a> Function<'a> {
|
|||
}
|
||||
Kind::BinOp { op: TokenKind::Add }
|
||||
if self.nodes.is_const(node.inputs[2])
|
||||
&& node
|
||||
.outputs
|
||||
.iter()
|
||||
.all(|&n| matches!(self.nodes[n].kind, Kind::Stre | Kind::Load)) =>
|
||||
&& node.outputs.iter().all(|&n| {
|
||||
matches!(self.nodes[n].kind, Kind::Stre | Kind::Load)
|
||||
&& self.tys.size_of(self.nodes[n].ty) <= 8
|
||||
}) =>
|
||||
{
|
||||
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);
|
||||
|
||||
for o in node.outputs.into_iter().rev() {
|
||||
|
@ -2851,6 +2899,10 @@ impl<'a> Function<'a> {
|
|||
let ops = vec![self.drg(nid)];
|
||||
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::Load { .. } => {
|
||||
let mut region = node.inputs[1];
|
||||
|
@ -3283,7 +3335,7 @@ mod tests {
|
|||
//struct_patterns;
|
||||
arrays;
|
||||
//inline;
|
||||
//idk;
|
||||
idk;
|
||||
//wide_ret;
|
||||
|
||||
// Incomplete Examples;
|
||||
|
|
|
@ -1,11 +1,36 @@
|
|||
main:
|
||||
ADDI64 r254, r254, -16d
|
||||
ST r31, r254, 0a, 16h
|
||||
LI64 r32, 1610612737d
|
||||
LI64 r1, 0d
|
||||
LD r31, r254, 0a, 16h
|
||||
ADDI64 r254, r254, 16d
|
||||
ADDI64 r254, r254, -8d
|
||||
ST r31, r254, 0a, 8h
|
||||
LI64 r2, 1d
|
||||
JAL r31, r0, :sqrt
|
||||
LD r31, r254, 0a, 8h
|
||||
ADDI64 r254, r254, 8d
|
||||
JALA r0, r31, 0a
|
||||
code size: 87
|
||||
ret: 0
|
||||
sqrt:
|
||||
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(())
|
||||
|
|
|
@ -14,12 +14,13 @@ main:
|
|||
ADDI64 r254, r254, 8d
|
||||
JALA r0, r31, 0a
|
||||
outl:
|
||||
ADDI64 r254, r254, -16d
|
||||
ST r31, r254, 0a, 16h
|
||||
ADDI64 r254, r254, -24d
|
||||
ST r31, r254, 0a, 24h
|
||||
LRA r32, r0, :"whahaha\0"
|
||||
LD r31, r254, 0a, 16h
|
||||
ADDI64 r254, r254, 16d
|
||||
LI64 r33, 0d
|
||||
LD r31, r254, 0a, 24h
|
||||
ADDI64 r254, r254, 24d
|
||||
JALA r0, r31, 0a
|
||||
code size: 229
|
||||
code size: 239
|
||||
ret: 0
|
||||
status: Ok(())
|
||||
|
|
19
lang/tests/son_tests_idk.txt
Normal file
19
lang/tests/son_tests_idk.txt
Normal 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(())
|
|
@ -1,7 +1,7 @@
|
|||
main:
|
||||
ADDI64 r254, r254, -8d
|
||||
ST r31, r254, 0a, 8h
|
||||
LI64 r2, 1d
|
||||
LI64 r2, 100d
|
||||
JAL r31, r0, :sqrt
|
||||
LD r31, r254, 0a, 8h
|
||||
ADDI64 r254, r254, 8d
|
||||
|
@ -25,5 +25,5 @@ sqrt:
|
|||
JMP :3
|
||||
1: JALA r0, r31, 0a
|
||||
code size: 188
|
||||
ret: 0
|
||||
ret: 14
|
||||
status: Ok(())
|
||||
|
|
Loading…
Reference in a new issue