From 641d344d2dcdf9392f6506831f5ccc31ed5e2ab8 Mon Sep 17 00:00:00 2001 From: mlokr Date: Thu, 12 Sep 2024 18:42:21 +0200 Subject: [PATCH] removing false positives --- hblang/README.md | 2 + hblang/src/codegen.rs | 15 +- hblang/src/lib.rs | 3 +- hblang/src/son.rs | 355 +++++++++++++----- ...ts_comptime_function_from_another_file.txt | 2 +- .../tests/codegen_tests_global_variables.txt | 2 +- hblang/tests/codegen_tests_if_statements.txt | 5 +- hblang/tests/codegen_tests_inline_test.txt | 14 +- ...codegen_tests_integer_inference_issues.txt | 5 +- hblang/tests/codegen_tests_loops.txt | 5 +- hblang/tests/codegen_tests_request_page.txt | 5 +- .../tests/codegen_tests_struct_patterns.txt | 11 +- 12 files changed, 300 insertions(+), 124 deletions(-) diff --git a/hblang/README.md b/hblang/README.md index 4d73b38..1e467b7 100644 --- a/hblang/README.md +++ b/hblang/README.md @@ -337,6 +337,8 @@ foo := fn(a: int, b: int, c: int): int { #### idk ```hb +_edge_case := @as(int, idk) + main := fn(): int { big_array := @as([u8; 128], idk) i := 0 diff --git a/hblang/src/codegen.rs b/hblang/src/codegen.rs index 2a9d6b7..75dbca7 100644 --- a/hblang/src/codegen.rs +++ b/hblang/src/codegen.rs @@ -1648,12 +1648,15 @@ impl Codegen { }; if ctx.loc.is_some() { - self.report( - pos, - "`idk` would be written to an existing memory location \ - which at ths point does notthing so its prohibited. TODO: make debug \ - builds write 0xAA instead.", - ); + // self.report( + // pos, + // format_args!( + // "`idk` would be written to an existing memory location \ + // which at ths point does notthing so its prohibited. TODO: make debug \ + // builds write 0xAA instead. Info for weak people: {:?}", + // ctx.loc + // ), + // ); } let loc = match self.tys.size_of(ty) { diff --git a/hblang/src/lib.rs b/hblang/src/lib.rs index c17ffc2..0f7f90d 100644 --- a/hblang/src/lib.rs +++ b/hblang/src/lib.rs @@ -15,7 +15,8 @@ slice_ptr_get, slice_take, map_try_insert, - extract_if + extract_if, + ptr_internals )] #![allow(internal_features, clippy::format_collect)] diff --git a/hblang/src/son.rs b/hblang/src/son.rs index 1bf5e91..1033bc6 100644 --- a/hblang/src/son.rs +++ b/hblang/src/son.rs @@ -18,8 +18,9 @@ use { collections::{hash_map, BTreeMap}, fmt::{Display, Write}, hash::{Hash as _, Hasher}, - mem, - ops::{self, Range}, + mem::{self, MaybeUninit}, + ops::{self, Deref, DerefMut, Range}, + ptr::Unique, rc::Rc, }, }; @@ -44,6 +45,108 @@ impl Drop for Drom { } } +const VC_SIZE: usize = std::mem::size_of::(); +const INLINE_ELEMS: usize = VC_SIZE / std::mem::size_of::() - 1; + +union Vc { + inline: InlineVc, + alloced: AllocedVc, +} + +impl Vc { + fn is_inline(&self) -> bool { + unsafe { self.inline.len <= INLINE_ELEMS as u32 } + } + + fn layout(&self) -> Option { + unsafe { + self.is_inline() + .then(|| std::alloc::Layout::array::(self.alloced.cap as _).unwrap_unchecked()) + } + } + + fn len(&self) -> usize { + unsafe { self.inline.len as _ } + } + + fn as_ptr(&self) -> *mut Nid { + unsafe { + match self.is_inline() { + true => self.alloced.base.as_ptr(), + false => { self.inline.elems }.as_mut_ptr().cast(), + } + } + } + + fn as_slice(&self) -> &[Nid] { + unsafe { std::slice::from_raw_parts(self.as_ptr(), self.len()) } + } + + fn as_slice_mut(&mut self) -> &mut [Nid] { + unsafe { std::slice::from_raw_parts_mut(self.as_ptr(), self.len()) } + } +} + +impl Drop for Vc { + fn drop(&mut self) { + if let Some(layout) = self.layout() { + unsafe { + std::alloc::dealloc(self.alloced.base.as_ptr().cast(), layout); + } + } + } +} + +impl Clone for Vc { + fn clone(&self) -> Self { + if self.is_inline() { + unsafe { std::ptr::read(self) } + } else { + let layout = unsafe { std::alloc::Layout::array::(self.len()).unwrap_unchecked() }; + let alloc = unsafe { std::alloc::alloc(layout) }; + unsafe { std::ptr::copy_nonoverlapping(self.as_ptr(), alloc.cast(), self.len()) }; + unsafe { + Vc { + alloced: AllocedVc { + base: Unique::new_unchecked(alloc.cast()), + len: self.alloced.len, + cap: self.alloced.cap, + }, + } + } + } + } +} + +impl Deref for Vc { + type Target = [Nid]; + + fn deref(&self) -> &Self::Target { + self.as_slice() + } +} + +impl DerefMut for Vc { + fn deref_mut(&mut self) -> &mut Self::Target { + self.as_slice_mut() + } +} + +#[derive(Clone, Copy)] +#[repr(C)] +struct InlineVc { + elems: MaybeUninit<[Nid; INLINE_ELEMS]>, + len: Nid, +} + +#[derive(Clone, Copy)] +#[repr(C)] +struct AllocedVc { + base: Unique, + cap: u32, + len: u32, +} + #[derive(Default)] struct BitSet { data: Vec, @@ -539,8 +642,7 @@ impl Nodes { ) -> Nid { let ty = ty.into(); - let node = - Node { inputs: inps.into(), kind, color: 0, depth: 0, lock_rc: 0, ty, outputs: vec![] }; + let node = Node { inputs: inps.into(), kind, ty, ..Default::default() }; let mut lookup_meta = None; if !node.is_lazy_phi() { @@ -916,17 +1018,15 @@ impl Nodes { #[allow(clippy::format_in_format_args)] fn basic_blocks_instr(&mut self, out: &mut String, node: Nid) -> std::fmt::Result { - if !self.visited.set(node as _) { - return Ok(()); + if self[node].kind != Kind::Loop && self[node].kind != Kind::Region { + write!(out, " {node:>2}: ")?; } - write!(out, " {node:>2}: ")?; match self[node].kind { Kind::Start => unreachable!(), Kind::End => unreachable!(), Kind::If => write!(out, " if: "), - Kind::Region => unreachable!(), - Kind::Loop => unreachable!(), - Kind::Return => write!(out, " ret: "), + Kind::Region | Kind::Loop => writeln!(out, " goto: {node}"), + Kind::Return => write!(out, " ret: "), Kind::CInt { value } => write!(out, "cint: #{value:<4}"), Kind::Phi => write!(out, " phi: "), Kind::Tuple { index } => write!(out, " arg: {index:<5}"), @@ -934,66 +1034,65 @@ impl Nodes { write!(out, "{:>4}: ", op.name()) } Kind::Call { func } => { - write!(out, "call: {func} {}", self[node].depth) + write!(out, "call: {func} {} ", self[node].depth) } }?; - writeln!( - out, - " {:<14} {}", - format!("{:?}", self[node].inputs), - format!("{:?}", self[node].outputs) - ) + if self[node].kind != Kind::Loop && self[node].kind != Kind::Region { + writeln!( + out, + " {:<14} {}", + format!("{:?}", self[node].inputs), + format!("{:?}", self[node].outputs) + )?; + } + + Ok(()) } fn basic_blocks_low(&mut self, out: &mut String, mut node: Nid) -> std::fmt::Result { + let iter = |nodes: &Nodes, node| nodes[node].outputs.clone().into_iter().rev(); while self.visited.set(node as _) { - match dbg!(self[node].kind) { + match self[node].kind { Kind::Start => { writeln!(out, "start: {}", self[node].depth)?; let mut cfg_index = Nid::MAX; - for o in self[node].outputs.clone() { + for o in iter(self, node) { + self.basic_blocks_instr(out, o)?; if self[o].kind == (Kind::Tuple { index: 0 }) { cfg_index = o; - continue; } - self.basic_blocks_instr(out, o)?; } node = cfg_index; } Kind::End => break, Kind::If => { - self.visited.unset(node as _); - self.basic_blocks_instr(out, node)?; self.basic_blocks_low(out, self[node].outputs[0])?; node = self[node].outputs[1]; } Kind::Region => { + writeln!(out, "region{node}: {}", self[node].depth)?; let mut cfg_index = Nid::MAX; - for o in self[node].outputs.clone().into_iter() { + for o in iter(self, node) { + self.basic_blocks_instr(out, o)?; if self.is_cfg(o) { cfg_index = o; - continue; } - self.basic_blocks_instr(out, o)?; } node = cfg_index; } Kind::Loop => { - writeln!(out, "loop{node} {}", self[node].depth)?; + writeln!(out, "loop{node}: {}", self[node].depth)?; let mut cfg_index = Nid::MAX; - for o in self[node].outputs.clone().into_iter() { + for o in iter(self, node) { + self.basic_blocks_instr(out, o)?; if self.is_cfg(o) { cfg_index = o; - continue; } - self.basic_blocks_instr(out, o)?; } node = cfg_index; } Kind::Return => { - self.visited.unset(node as _); - self.basic_blocks_instr(out, node)?; node = self[node].outputs[0]; } Kind::CInt { .. } => unreachable!(), @@ -1001,34 +1100,24 @@ impl Nodes { Kind::Tuple { .. } => { writeln!(out, "b{node}: {}", self[node].depth)?; let mut cfg_index = Nid::MAX; - for o in self[node].outputs.clone().into_iter() { + for o in iter(self, node) { + self.basic_blocks_instr(out, o)?; if self.is_cfg(o) { cfg_index = o; - continue; } - self.basic_blocks_instr(out, o)?; - } - if !self[cfg_index].kind.ends_basic_block() - && !matches!(self[cfg_index].kind, Kind::Call { .. }) - { - writeln!(out, " goto: {cfg_index}")?; } node = cfg_index; } Kind::BinOp { .. } => unreachable!(), Kind::Call { .. } => { - self.visited.unset(node as _); - self.basic_blocks_instr(out, node)?; - let mut cfg_index = Nid::MAX; - for o in self[node].outputs.clone().into_iter() { - if self.is_cfg(o) { - cfg_index = o; - continue; - } + for o in iter(self, node) { if self[o].inputs[0] == node { self.basic_blocks_instr(out, o)?; } + if self.is_cfg(o) { + cfg_index = o; + } } node = cfg_index; } @@ -1042,7 +1131,7 @@ impl Nodes { let mut out = String::new(); self.visited.clear(self.values.len()); self.basic_blocks_low(&mut out, 0).unwrap(); - println!("{out}"); + eprintln!("{out}"); } fn graphviz(&self) { @@ -1182,20 +1271,29 @@ impl ops::IndexMut for Nodes { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default)] #[repr(u8)] pub enum Kind { + #[default] Start, End, If, Region, Loop, Return, - CInt { value: i64 }, + CInt { + value: i64, + }, Phi, - Tuple { index: u32 }, - BinOp { op: lexer::TokenKind }, - Call { func: ty::Func }, + Tuple { + index: u32, + }, + BinOp { + op: lexer::TokenKind, + }, + Call { + func: ty::Func, + }, } impl Kind { @@ -1238,7 +1336,7 @@ impl fmt::Display for Kind { } } -#[derive(Debug)] +#[derive(Debug, Default)] struct Node { inputs: Vec, outputs: Vec, @@ -1247,6 +1345,7 @@ struct Node { depth: u32, lock_rc: u32, ty: ty::Id, + loop_depth: u32, } impl Node { @@ -2012,6 +2111,13 @@ impl Codegen { self.ci.nodes.modify_input(node, 1, self.ci.ctrl); + let idx = self.ci.nodes[node] + .outputs + .iter() + .position(|&n| self.ci.nodes.is_cfg(n)) + .unwrap(); + self.ci.nodes[node].outputs.swap(idx, 0); + self.ci.ctrl = bre; if bre == Nid::MAX { return None; @@ -3255,6 +3361,47 @@ impl Codegen { } fn gcm(&mut self) { + fn loop_depth(target: Nid, nodes: &mut Nodes) -> u32 { + if nodes[target].loop_depth != 0 { + return nodes[target].loop_depth; + } + + nodes[target].loop_depth = match nodes[target].kind { + Kind::Tuple { .. } | Kind::Call { .. } | Kind::Return | Kind::If => { + loop_depth(nodes[target].inputs[0], nodes) + } + Kind::Region => loop_depth(idom(nodes, target), nodes), + Kind::Loop => { + let depth = loop_depth(nodes[target].inputs[0], nodes) + 1; + let mut cursor = nodes[target].inputs[1]; + while cursor != target { + nodes[cursor].loop_depth = depth; + let next = idom(nodes, cursor); + if let Kind::Tuple { index } = nodes[cursor].kind + && nodes[next].kind == Kind::If + { + let other = *nodes[next].outputs.iter().find(|&&n| matches!(nodes[n].kind, Kind::Tuple { index: oi } if index != oi)).unwrap(); + nodes[other].loop_depth = depth - 1; + } + cursor = next; + } + depth + } + Kind::Start | Kind::End => 1, + Kind::CInt { .. } | Kind::Phi | Kind::BinOp { .. } => { + unreachable!() + } + }; + + nodes[target].loop_depth + } + + fn better(nodes: &mut Nodes, is: Nid, then: Nid) -> bool { + loop_depth(is, nodes) < loop_depth(then, nodes) + || idepth(nodes, is) > idepth(nodes, then) + || nodes[then].kind == Kind::If + } + fn idepth(nodes: &mut Nodes, target: Nid) -> u32 { if target == 0 { return 0; @@ -3279,21 +3426,8 @@ impl Codegen { | Kind::Return | Kind::If => nodes[target].inputs[0], Kind::Region => { - let &[mut lcfg, mut rcfg] = nodes[target].inputs.as_slice() else { - unreachable!() - }; - - while lcfg != rcfg { - let [ldepth, rdepth] = [idepth(nodes, lcfg), idepth(nodes, rcfg)]; - if ldepth >= rdepth { - lcfg = idom(nodes, lcfg); - } - if ldepth <= rdepth { - rcfg = idom(nodes, rcfg); - } - } - - lcfg + let &[lcfg, rcfg] = nodes[target].inputs.as_slice() else { unreachable!() }; + common_dom(lcfg, rcfg, nodes) } } } @@ -3340,7 +3474,7 @@ impl Codegen { } } - fn push_down(nodes: &mut Nodes, node: Nid, lowest_pos: &mut [u32]) { + fn push_down(nodes: &mut Nodes, node: Nid) { if !nodes.visited.set(node as _) { return; } @@ -3348,47 +3482,72 @@ impl Codegen { // TODO: handle memory nodes first if nodes[node].kind.is_pinned() { - for i in 0..nodes[node].inputs.len() { - let i = nodes[node].inputs[i]; - push_up(nodes, i); + // TODO: use buffer to avoid allocation or better yet queue the location changes + for i in nodes[node].outputs.clone() { + push_down(nodes, i); } } else { - let mut max = 0; - for i in 0..nodes[node].inputs.len() { - let i = nodes[node].inputs[i]; - let is_call = matches!(nodes[i].kind, Kind::Call { .. }); - if nodes.is_cfg(i) && !is_call { - continue; + let mut min = None::; + for i in 0..nodes[node].outputs.len() { + let i = nodes[node].outputs[i]; + push_down(nodes, i); + let i = use_block(node, i, nodes); + min = min.map(|m| common_dom(i, m, nodes)).or(Some(i)); + } + let mut min = min.unwrap(); + + let mut cursor = min; + loop { + if better(nodes, cursor, min) { + min = cursor; } - push_up(nodes, i); - if idepth(nodes, i) > idepth(nodes, max) { - max = if is_call { i } else { idom(nodes, i) }; + if cursor == nodes[node].inputs[0] { + break; } + cursor = idom(nodes, cursor); } - if max == 0 { - return; + if nodes[min].kind.ends_basic_block() { + min = idom(nodes, min); } - let index = nodes[0].outputs.iter().position(|&p| p == node).unwrap(); - nodes[0].outputs.remove(index); - nodes[node].inputs[0] = max; - debug_assert!( - !nodes[max].outputs.contains(&node) - || matches!(nodes[max].kind, Kind::Call { .. }), - "{node} {:?} {max} {:?}", - nodes[node], - nodes[max] - ); - nodes[max].outputs.push(node); + let prev = nodes[node].inputs[0]; + if min != prev { + let index = nodes[prev].outputs.iter().position(|&p| p == node).unwrap(); + nodes[prev].outputs.remove(index); + nodes[node].inputs[0] = min; + nodes[min].outputs.push(node); + } } } + fn use_block(target: Nid, from: Nid, nodes: &mut Nodes) -> Nid { + if nodes[from].kind != Kind::Phi { + return idom(nodes, from); + } + + let index = nodes[from].inputs.iter().position(|&n| n == target).unwrap(); + nodes[nodes[from].inputs[0]].inputs[index - 1] + } + + fn common_dom(mut a: Nid, mut b: Nid, nodes: &mut Nodes) -> Nid { + while a != b { + let [ldepth, rdepth] = [idepth(nodes, a), idepth(nodes, b)]; + if ldepth >= rdepth { + a = idom(nodes, a); + } + if ldepth <= rdepth { + b = idom(nodes, b); + } + } + a + } + self.ci.nodes.visited.clear(self.ci.nodes.values.len()); push_up(&mut self.ci.nodes, self.ci.end); // TODO: handle infinte loops self.ci.nodes.visited.clear(self.ci.nodes.values.len()); - //push_down(&mut self.ci.nodes, self.ci.start); + push_down(&mut self.ci.nodes, self.ci.start); } } @@ -3626,6 +3785,6 @@ mod tests { const_folding_with_arg => README; // FIXME: contains redundant copies branch_assignments => README; - //exhaustive_loop_testing => README; + exhaustive_loop_testing => README; } } diff --git a/hblang/tests/codegen_tests_comptime_function_from_another_file.txt b/hblang/tests/codegen_tests_comptime_function_from_another_file.txt index d91d03f..39a050a 100644 --- a/hblang/tests/codegen_tests_comptime_function_from_another_file.txt +++ b/hblang/tests/codegen_tests_comptime_function_from_another_file.txt @@ -6,6 +6,6 @@ main: LD r31, r254, 0a, 16h ADDI64 r254, r254, 16d JALA r0, r31, 0a -code size: 236 +code size: 239 ret: 50 status: Ok(()) diff --git a/hblang/tests/codegen_tests_global_variables.txt b/hblang/tests/codegen_tests_global_variables.txt index 6a48158..181df45 100644 --- a/hblang/tests/codegen_tests_global_variables.txt +++ b/hblang/tests/codegen_tests_global_variables.txt @@ -11,6 +11,6 @@ main: LD r31, r254, 0a, 32h ADDI64 r254, r254, 32d JALA r0, r31, 0a -code size: 296 +code size: 299 ret: 55 status: Ok(()) diff --git a/hblang/tests/codegen_tests_if_statements.txt b/hblang/tests/codegen_tests_if_statements.txt index 541f436..dcdada4 100644 --- a/hblang/tests/codegen_tests_if_statements.txt +++ b/hblang/tests/codegen_tests_if_statements.txt @@ -14,7 +14,8 @@ fib: JGTS r32, r33, :0 LI64 r1, 1d JMP :1 - 0: ADDI64 r33, r32, -1d + 0: CP r33, r32 + ADDI64 r33, r33, -1d CP r2, r33 JAL r31, r0, :fib CP r33, r1 @@ -26,6 +27,6 @@ fib: 1: LD r31, r254, 0a, 24h ADDI64 r254, r254, 24d JALA r0, r31, 0a -code size: 228 +code size: 231 ret: 55 status: Ok(()) diff --git a/hblang/tests/codegen_tests_inline_test.txt b/hblang/tests/codegen_tests_inline_test.txt index 691ddf3..514c31c 100644 --- a/hblang/tests/codegen_tests_inline_test.txt +++ b/hblang/tests/codegen_tests_inline_test.txt @@ -57,10 +57,11 @@ example: CMPUI r35, r35, 0d OR r34, r34, r35 JEQ r34, r0, :0 + CP r34, r33 LI64 r35, 1024d ADDI64 r35, r35, 0d ADDI64 r35, r35, 1d - DIRS64 r0, r34, r33, r35 + DIRS64 r0, r34, r34, r35 ADDI64 r32, r34, 0d JMP :1 0: CP r32, r33 @@ -82,17 +83,20 @@ integer: LI64 r3, 4d ECA CP r34, r1 + CP r35, r32 LI64 r36, 0d - CMPS r35, r32, r36 + CMPS r35, r35, r36 CMPUI r35, r35, 0d + CP r36, r33 LI64 r37, 0d - CMPS r36, r33, r37 + CMPS r36, r36, r37 CMPUI r36, r36, 0d OR r35, r35, r36 JEQ r35, r0, :0 + CP r35, r34 SUB64 r33, r33, r32 ADDI64 r33, r33, 1d - DIRS64 r0, r35, r34, r33 + DIRS64 r0, r35, r35, r33 ADD64 r1, r35, r32 JMP :1 0: CP r1, r34 @@ -152,6 +156,6 @@ line: 2: LD r31, r254, 48a, 32h ADDI64 r254, r254, 80d JALA r0, r31, 0a -code size: 1404 +code size: 1416 ret: 0 status: Ok(()) diff --git a/hblang/tests/codegen_tests_integer_inference_issues.txt b/hblang/tests/codegen_tests_integer_inference_issues.txt index 48b1d3c..3558654 100644 --- a/hblang/tests/codegen_tests_integer_inference_issues.txt +++ b/hblang/tests/codegen_tests_integer_inference_issues.txt @@ -16,13 +16,14 @@ integer_range: LI64 r2, 3d LI64 r3, 4d ECA + CP r34, r1 SUB64 r33, r33, r32 ADDI64 r33, r33, 1d - DIRU64 r0, r34, r1, r33 + DIRU64 r0, r34, r34, r33 ADD64 r1, r34, r32 LD r31, r254, 0a, 32h ADDI64 r254, r254, 32d JALA r0, r31, 0a -code size: 211 +code size: 214 ret: 42 status: Ok(()) diff --git a/hblang/tests/codegen_tests_loops.txt b/hblang/tests/codegen_tests_loops.txt index 58d0381..e82279f 100644 --- a/hblang/tests/codegen_tests_loops.txt +++ b/hblang/tests/codegen_tests_loops.txt @@ -15,7 +15,8 @@ fib: 2: LI64 r35, 0d JNE r32, r35, :0 JMP :1 - 0: ADD64 r35, r33, r34 + 0: CP r35, r33 + ADD64 r35, r35, r34 CP r33, r34 CP r34, r35 ADDI64 r32, r32, -1d @@ -24,6 +25,6 @@ fib: LD r31, r254, 0a, 40h ADDI64 r254, r254, 40d JALA r0, r31, 0a -code size: 215 +code size: 218 ret: 55 status: Ok(()) diff --git a/hblang/tests/codegen_tests_request_page.txt b/hblang/tests/codegen_tests_request_page.txt index c36cfb9..a85f4d4 100644 --- a/hblang/tests/codegen_tests_request_page.txt +++ b/hblang/tests/codegen_tests_request_page.txt @@ -43,7 +43,8 @@ request_page: ST r31, r254, 0a, 32h CP r32, r2 LRA r33, r0, :"\0\u{1}xxxxxxxx" - ADDI64 r34, r33, 1d + CP r34, r33 + ADDI64 r34, r34, 1d ST r32, r34, 0a, 1h LI64 r2, 3d LI64 r3, 2d @@ -53,6 +54,6 @@ request_page: LD r31, r254, 0a, 32h ADDI64 r254, r254, 32d JALA r0, r31, 0a -code size: 440 +code size: 443 ret: 42 status: Ok(()) diff --git a/hblang/tests/codegen_tests_struct_patterns.txt b/hblang/tests/codegen_tests_struct_patterns.txt index da677f2..aee57f7 100644 --- a/hblang/tests/codegen_tests_struct_patterns.txt +++ b/hblang/tests/codegen_tests_struct_patterns.txt @@ -28,7 +28,8 @@ fib_iter: 2: LI64 r35, 0d JNE r32, r35, :0 JMP :1 - 0: ADD64 r35, r33, r34 + 0: CP r35, r33 + ADD64 r35, r35, r34 CP r33, r34 CP r34, r35 ADDI64 r32, r32, -1d @@ -43,11 +44,13 @@ fib: CP r32, r2 LI64 r33, 2d JLTS r32, r33, :0 - ADDI64 r33, r32, -1d + CP r33, r32 + ADDI64 r33, r33, -1d CP r2, r33 JAL r31, r0, :fib CP r33, r1 - ADDI64 r34, r32, -2d + CP r34, r32 + ADDI64 r34, r34, -2d CP r2, r34 JAL r31, r0, :fib CP r34, r1 @@ -57,6 +60,6 @@ fib: 1: LD r31, r254, 0a, 32h ADDI64 r254, r254, 32d JALA r0, r31, 0a -code size: 455 +code size: 464 ret: 0 status: Ok(())