removing false positives

This commit is contained in:
mlokr 2024-09-12 18:42:21 +02:00
parent dc418bd5e0
commit 641d344d2d
No known key found for this signature in database
GPG key ID: DEA147DDEE644993
12 changed files with 300 additions and 124 deletions

View file

@ -337,6 +337,8 @@ foo := fn(a: int, b: int, c: int): int {
#### idk #### idk
```hb ```hb
_edge_case := @as(int, idk)
main := fn(): int { main := fn(): int {
big_array := @as([u8; 128], idk) big_array := @as([u8; 128], idk)
i := 0 i := 0

View file

@ -1648,12 +1648,15 @@ impl Codegen {
}; };
if ctx.loc.is_some() { if ctx.loc.is_some() {
self.report( // self.report(
pos, // pos,
"`idk` would be written to an existing memory location \ // format_args!(
which at ths point does notthing so its prohibited. TODO: make debug \ // "`idk` would be written to an existing memory location \
builds write 0xAA instead.", // 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) { let loc = match self.tys.size_of(ty) {

View file

@ -15,7 +15,8 @@
slice_ptr_get, slice_ptr_get,
slice_take, slice_take,
map_try_insert, map_try_insert,
extract_if extract_if,
ptr_internals
)] )]
#![allow(internal_features, clippy::format_collect)] #![allow(internal_features, clippy::format_collect)]

View file

@ -18,8 +18,9 @@ use {
collections::{hash_map, BTreeMap}, collections::{hash_map, BTreeMap},
fmt::{Display, Write}, fmt::{Display, Write},
hash::{Hash as _, Hasher}, hash::{Hash as _, Hasher},
mem, mem::{self, MaybeUninit},
ops::{self, Range}, ops::{self, Deref, DerefMut, Range},
ptr::Unique,
rc::Rc, rc::Rc,
}, },
}; };
@ -44,6 +45,108 @@ impl Drop for Drom {
} }
} }
const VC_SIZE: usize = std::mem::size_of::<AllocedVc>();
const INLINE_ELEMS: usize = VC_SIZE / std::mem::size_of::<Nid>() - 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<std::alloc::Layout> {
unsafe {
self.is_inline()
.then(|| std::alloc::Layout::array::<Nid>(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::<Nid>(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<Nid>,
cap: u32,
len: u32,
}
#[derive(Default)] #[derive(Default)]
struct BitSet { struct BitSet {
data: Vec<usize>, data: Vec<usize>,
@ -539,8 +642,7 @@ impl Nodes {
) -> Nid { ) -> Nid {
let ty = ty.into(); let ty = ty.into();
let node = let node = Node { inputs: inps.into(), kind, ty, ..Default::default() };
Node { inputs: inps.into(), kind, color: 0, depth: 0, lock_rc: 0, ty, outputs: vec![] };
let mut lookup_meta = None; let mut lookup_meta = None;
if !node.is_lazy_phi() { if !node.is_lazy_phi() {
@ -916,17 +1018,15 @@ impl Nodes {
#[allow(clippy::format_in_format_args)] #[allow(clippy::format_in_format_args)]
fn basic_blocks_instr(&mut self, out: &mut String, node: Nid) -> std::fmt::Result { fn basic_blocks_instr(&mut self, out: &mut String, node: Nid) -> std::fmt::Result {
if !self.visited.set(node as _) { if self[node].kind != Kind::Loop && self[node].kind != Kind::Region {
return Ok(()); write!(out, " {node:>2}: ")?;
} }
write!(out, " {node:>2}: ")?;
match self[node].kind { match self[node].kind {
Kind::Start => unreachable!(), Kind::Start => unreachable!(),
Kind::End => unreachable!(), Kind::End => unreachable!(),
Kind::If => write!(out, " if: "), Kind::If => write!(out, " if: "),
Kind::Region => unreachable!(), Kind::Region | Kind::Loop => writeln!(out, " goto: {node}"),
Kind::Loop => unreachable!(), Kind::Return => write!(out, " ret: "),
Kind::Return => write!(out, " ret: "),
Kind::CInt { value } => write!(out, "cint: #{value:<4}"), Kind::CInt { value } => write!(out, "cint: #{value:<4}"),
Kind::Phi => write!(out, " phi: "), Kind::Phi => write!(out, " phi: "),
Kind::Tuple { index } => write!(out, " arg: {index:<5}"), Kind::Tuple { index } => write!(out, " arg: {index:<5}"),
@ -934,66 +1034,65 @@ impl Nodes {
write!(out, "{:>4}: ", op.name()) write!(out, "{:>4}: ", op.name())
} }
Kind::Call { func } => { Kind::Call { func } => {
write!(out, "call: {func} {}", self[node].depth) write!(out, "call: {func} {} ", self[node].depth)
} }
}?; }?;
writeln!( if self[node].kind != Kind::Loop && self[node].kind != Kind::Region {
out, writeln!(
" {:<14} {}", out,
format!("{:?}", self[node].inputs), " {:<14} {}",
format!("{:?}", self[node].outputs) format!("{:?}", self[node].inputs),
) format!("{:?}", self[node].outputs)
)?;
}
Ok(())
} }
fn basic_blocks_low(&mut self, out: &mut String, mut node: Nid) -> std::fmt::Result { 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 _) { while self.visited.set(node as _) {
match dbg!(self[node].kind) { match self[node].kind {
Kind::Start => { Kind::Start => {
writeln!(out, "start: {}", self[node].depth)?; writeln!(out, "start: {}", self[node].depth)?;
let mut cfg_index = Nid::MAX; 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 }) { if self[o].kind == (Kind::Tuple { index: 0 }) {
cfg_index = o; cfg_index = o;
continue;
} }
self.basic_blocks_instr(out, o)?;
} }
node = cfg_index; node = cfg_index;
} }
Kind::End => break, Kind::End => break,
Kind::If => { Kind::If => {
self.visited.unset(node as _);
self.basic_blocks_instr(out, node)?;
self.basic_blocks_low(out, self[node].outputs[0])?; self.basic_blocks_low(out, self[node].outputs[0])?;
node = self[node].outputs[1]; node = self[node].outputs[1];
} }
Kind::Region => { Kind::Region => {
writeln!(out, "region{node}: {}", self[node].depth)?;
let mut cfg_index = Nid::MAX; 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) { if self.is_cfg(o) {
cfg_index = o; cfg_index = o;
continue;
} }
self.basic_blocks_instr(out, o)?;
} }
node = cfg_index; node = cfg_index;
} }
Kind::Loop => { Kind::Loop => {
writeln!(out, "loop{node} {}", self[node].depth)?; writeln!(out, "loop{node}: {}", self[node].depth)?;
let mut cfg_index = Nid::MAX; 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) { if self.is_cfg(o) {
cfg_index = o; cfg_index = o;
continue;
} }
self.basic_blocks_instr(out, o)?;
} }
node = cfg_index; node = cfg_index;
} }
Kind::Return => { Kind::Return => {
self.visited.unset(node as _);
self.basic_blocks_instr(out, node)?;
node = self[node].outputs[0]; node = self[node].outputs[0];
} }
Kind::CInt { .. } => unreachable!(), Kind::CInt { .. } => unreachable!(),
@ -1001,34 +1100,24 @@ impl Nodes {
Kind::Tuple { .. } => { Kind::Tuple { .. } => {
writeln!(out, "b{node}: {}", self[node].depth)?; writeln!(out, "b{node}: {}", self[node].depth)?;
let mut cfg_index = Nid::MAX; 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) { if self.is_cfg(o) {
cfg_index = 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; node = cfg_index;
} }
Kind::BinOp { .. } => unreachable!(), Kind::BinOp { .. } => unreachable!(),
Kind::Call { .. } => { Kind::Call { .. } => {
self.visited.unset(node as _);
self.basic_blocks_instr(out, node)?;
let mut cfg_index = Nid::MAX; let mut cfg_index = Nid::MAX;
for o in self[node].outputs.clone().into_iter() { for o in iter(self, node) {
if self.is_cfg(o) {
cfg_index = o;
continue;
}
if self[o].inputs[0] == node { if self[o].inputs[0] == node {
self.basic_blocks_instr(out, o)?; self.basic_blocks_instr(out, o)?;
} }
if self.is_cfg(o) {
cfg_index = o;
}
} }
node = cfg_index; node = cfg_index;
} }
@ -1042,7 +1131,7 @@ impl Nodes {
let mut out = String::new(); let mut out = String::new();
self.visited.clear(self.values.len()); self.visited.clear(self.values.len());
self.basic_blocks_low(&mut out, 0).unwrap(); self.basic_blocks_low(&mut out, 0).unwrap();
println!("{out}"); eprintln!("{out}");
} }
fn graphviz(&self) { fn graphviz(&self) {
@ -1182,20 +1271,29 @@ impl ops::IndexMut<u32> for Nodes {
} }
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
#[repr(u8)] #[repr(u8)]
pub enum Kind { pub enum Kind {
#[default]
Start, Start,
End, End,
If, If,
Region, Region,
Loop, Loop,
Return, Return,
CInt { value: i64 }, CInt {
value: i64,
},
Phi, Phi,
Tuple { index: u32 }, Tuple {
BinOp { op: lexer::TokenKind }, index: u32,
Call { func: ty::Func }, },
BinOp {
op: lexer::TokenKind,
},
Call {
func: ty::Func,
},
} }
impl Kind { impl Kind {
@ -1238,7 +1336,7 @@ impl fmt::Display for Kind {
} }
} }
#[derive(Debug)] #[derive(Debug, Default)]
struct Node { struct Node {
inputs: Vec<Nid>, inputs: Vec<Nid>,
outputs: Vec<Nid>, outputs: Vec<Nid>,
@ -1247,6 +1345,7 @@ struct Node {
depth: u32, depth: u32,
lock_rc: u32, lock_rc: u32,
ty: ty::Id, ty: ty::Id,
loop_depth: u32,
} }
impl Node { impl Node {
@ -2012,6 +2111,13 @@ impl Codegen {
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]
.outputs
.iter()
.position(|&n| self.ci.nodes.is_cfg(n))
.unwrap();
self.ci.nodes[node].outputs.swap(idx, 0);
self.ci.ctrl = bre; self.ci.ctrl = bre;
if bre == Nid::MAX { if bre == Nid::MAX {
return None; return None;
@ -3255,6 +3361,47 @@ impl Codegen {
} }
fn gcm(&mut self) { 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 { fn idepth(nodes: &mut Nodes, target: Nid) -> u32 {
if target == 0 { if target == 0 {
return 0; return 0;
@ -3279,21 +3426,8 @@ impl Codegen {
| Kind::Return | Kind::Return
| Kind::If => nodes[target].inputs[0], | Kind::If => nodes[target].inputs[0],
Kind::Region => { Kind::Region => {
let &[mut lcfg, mut rcfg] = nodes[target].inputs.as_slice() else { let &[lcfg, rcfg] = nodes[target].inputs.as_slice() else { unreachable!() };
unreachable!() common_dom(lcfg, rcfg, nodes)
};
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
} }
} }
} }
@ -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 _) { if !nodes.visited.set(node as _) {
return; return;
} }
@ -3348,47 +3482,72 @@ impl Codegen {
// TODO: handle memory nodes first // TODO: handle memory nodes first
if nodes[node].kind.is_pinned() { if nodes[node].kind.is_pinned() {
for i in 0..nodes[node].inputs.len() { // TODO: use buffer to avoid allocation or better yet queue the location changes
let i = nodes[node].inputs[i]; for i in nodes[node].outputs.clone() {
push_up(nodes, i); push_down(nodes, i);
} }
} else { } else {
let mut max = 0; let mut min = None::<Nid>;
for i in 0..nodes[node].inputs.len() { for i in 0..nodes[node].outputs.len() {
let i = nodes[node].inputs[i]; let i = nodes[node].outputs[i];
let is_call = matches!(nodes[i].kind, Kind::Call { .. }); push_down(nodes, i);
if nodes.is_cfg(i) && !is_call { let i = use_block(node, i, nodes);
continue; 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 cursor == nodes[node].inputs[0] {
if idepth(nodes, i) > idepth(nodes, max) { break;
max = if is_call { i } else { idom(nodes, i) };
} }
cursor = idom(nodes, cursor);
} }
if max == 0 { if nodes[min].kind.ends_basic_block() {
return; min = idom(nodes, min);
} }
let index = nodes[0].outputs.iter().position(|&p| p == node).unwrap(); let prev = nodes[node].inputs[0];
nodes[0].outputs.remove(index); if min != prev {
nodes[node].inputs[0] = max; let index = nodes[prev].outputs.iter().position(|&p| p == node).unwrap();
debug_assert!( nodes[prev].outputs.remove(index);
!nodes[max].outputs.contains(&node) nodes[node].inputs[0] = min;
|| matches!(nodes[max].kind, Kind::Call { .. }), nodes[min].outputs.push(node);
"{node} {:?} {max} {:?}", }
nodes[node],
nodes[max]
);
nodes[max].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()); self.ci.nodes.visited.clear(self.ci.nodes.values.len());
push_up(&mut self.ci.nodes, self.ci.end); push_up(&mut self.ci.nodes, self.ci.end);
// TODO: handle infinte loops // TODO: handle infinte loops
self.ci.nodes.visited.clear(self.ci.nodes.values.len()); 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; const_folding_with_arg => README;
// FIXME: contains redundant copies // FIXME: contains redundant copies
branch_assignments => README; branch_assignments => README;
//exhaustive_loop_testing => README; exhaustive_loop_testing => README;
} }
} }

View file

@ -6,6 +6,6 @@ main:
LD r31, r254, 0a, 16h LD r31, r254, 0a, 16h
ADDI64 r254, r254, 16d ADDI64 r254, r254, 16d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 236 code size: 239
ret: 50 ret: 50
status: Ok(()) status: Ok(())

View file

@ -11,6 +11,6 @@ main:
LD r31, r254, 0a, 32h LD r31, r254, 0a, 32h
ADDI64 r254, r254, 32d ADDI64 r254, r254, 32d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 296 code size: 299
ret: 55 ret: 55
status: Ok(()) status: Ok(())

View file

@ -14,7 +14,8 @@ fib:
JGTS r32, r33, :0 JGTS r32, r33, :0
LI64 r1, 1d LI64 r1, 1d
JMP :1 JMP :1
0: ADDI64 r33, r32, -1d 0: CP r33, r32
ADDI64 r33, r33, -1d
CP r2, r33 CP r2, r33
JAL r31, r0, :fib JAL r31, r0, :fib
CP r33, r1 CP r33, r1
@ -26,6 +27,6 @@ fib:
1: LD r31, r254, 0a, 24h 1: LD r31, r254, 0a, 24h
ADDI64 r254, r254, 24d ADDI64 r254, r254, 24d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 228 code size: 231
ret: 55 ret: 55
status: Ok(()) status: Ok(())

View file

@ -57,10 +57,11 @@ example:
CMPUI r35, r35, 0d CMPUI r35, r35, 0d
OR r34, r34, r35 OR r34, r34, r35
JEQ r34, r0, :0 JEQ r34, r0, :0
CP r34, r33
LI64 r35, 1024d LI64 r35, 1024d
ADDI64 r35, r35, 0d ADDI64 r35, r35, 0d
ADDI64 r35, r35, 1d ADDI64 r35, r35, 1d
DIRS64 r0, r34, r33, r35 DIRS64 r0, r34, r34, r35
ADDI64 r32, r34, 0d ADDI64 r32, r34, 0d
JMP :1 JMP :1
0: CP r32, r33 0: CP r32, r33
@ -82,17 +83,20 @@ integer:
LI64 r3, 4d LI64 r3, 4d
ECA ECA
CP r34, r1 CP r34, r1
CP r35, r32
LI64 r36, 0d LI64 r36, 0d
CMPS r35, r32, r36 CMPS r35, r35, r36
CMPUI r35, r35, 0d CMPUI r35, r35, 0d
CP r36, r33
LI64 r37, 0d LI64 r37, 0d
CMPS r36, r33, r37 CMPS r36, r36, r37
CMPUI r36, r36, 0d CMPUI r36, r36, 0d
OR r35, r35, r36 OR r35, r35, r36
JEQ r35, r0, :0 JEQ r35, r0, :0
CP r35, r34
SUB64 r33, r33, r32 SUB64 r33, r33, r32
ADDI64 r33, r33, 1d ADDI64 r33, r33, 1d
DIRS64 r0, r35, r34, r33 DIRS64 r0, r35, r35, r33
ADD64 r1, r35, r32 ADD64 r1, r35, r32
JMP :1 JMP :1
0: CP r1, r34 0: CP r1, r34
@ -152,6 +156,6 @@ line:
2: LD r31, r254, 48a, 32h 2: LD r31, r254, 48a, 32h
ADDI64 r254, r254, 80d ADDI64 r254, r254, 80d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 1404 code size: 1416
ret: 0 ret: 0
status: Ok(()) status: Ok(())

View file

@ -16,13 +16,14 @@ integer_range:
LI64 r2, 3d LI64 r2, 3d
LI64 r3, 4d LI64 r3, 4d
ECA ECA
CP r34, r1
SUB64 r33, r33, r32 SUB64 r33, r33, r32
ADDI64 r33, r33, 1d ADDI64 r33, r33, 1d
DIRU64 r0, r34, r1, r33 DIRU64 r0, r34, r34, r33
ADD64 r1, r34, r32 ADD64 r1, r34, r32
LD r31, r254, 0a, 32h LD r31, r254, 0a, 32h
ADDI64 r254, r254, 32d ADDI64 r254, r254, 32d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 211 code size: 214
ret: 42 ret: 42
status: Ok(()) status: Ok(())

View file

@ -15,7 +15,8 @@ fib:
2: LI64 r35, 0d 2: LI64 r35, 0d
JNE r32, r35, :0 JNE r32, r35, :0
JMP :1 JMP :1
0: ADD64 r35, r33, r34 0: CP r35, r33
ADD64 r35, r35, r34
CP r33, r34 CP r33, r34
CP r34, r35 CP r34, r35
ADDI64 r32, r32, -1d ADDI64 r32, r32, -1d
@ -24,6 +25,6 @@ fib:
LD r31, r254, 0a, 40h LD r31, r254, 0a, 40h
ADDI64 r254, r254, 40d ADDI64 r254, r254, 40d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 215 code size: 218
ret: 55 ret: 55
status: Ok(()) status: Ok(())

View file

@ -43,7 +43,8 @@ request_page:
ST r31, r254, 0a, 32h ST r31, r254, 0a, 32h
CP r32, r2 CP r32, r2
LRA r33, r0, :"\0\u{1}xxxxxxxx" LRA r33, r0, :"\0\u{1}xxxxxxxx"
ADDI64 r34, r33, 1d CP r34, r33
ADDI64 r34, r34, 1d
ST r32, r34, 0a, 1h ST r32, r34, 0a, 1h
LI64 r2, 3d LI64 r2, 3d
LI64 r3, 2d LI64 r3, 2d
@ -53,6 +54,6 @@ request_page:
LD r31, r254, 0a, 32h LD r31, r254, 0a, 32h
ADDI64 r254, r254, 32d ADDI64 r254, r254, 32d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 440 code size: 443
ret: 42 ret: 42
status: Ok(()) status: Ok(())

View file

@ -28,7 +28,8 @@ fib_iter:
2: LI64 r35, 0d 2: LI64 r35, 0d
JNE r32, r35, :0 JNE r32, r35, :0
JMP :1 JMP :1
0: ADD64 r35, r33, r34 0: CP r35, r33
ADD64 r35, r35, r34
CP r33, r34 CP r33, r34
CP r34, r35 CP r34, r35
ADDI64 r32, r32, -1d ADDI64 r32, r32, -1d
@ -43,11 +44,13 @@ fib:
CP r32, r2 CP r32, r2
LI64 r33, 2d LI64 r33, 2d
JLTS r32, r33, :0 JLTS r32, r33, :0
ADDI64 r33, r32, -1d CP r33, r32
ADDI64 r33, r33, -1d
CP r2, r33 CP r2, r33
JAL r31, r0, :fib JAL r31, r0, :fib
CP r33, r1 CP r33, r1
ADDI64 r34, r32, -2d CP r34, r32
ADDI64 r34, r34, -2d
CP r2, r34 CP r2, r34
JAL r31, r0, :fib JAL r31, r0, :fib
CP r34, r1 CP r34, r1
@ -57,6 +60,6 @@ fib:
1: LD r31, r254, 0a, 32h 1: LD r31, r254, 0a, 32h
ADDI64 r254, r254, 32d ADDI64 r254, r254, 32d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 455 code size: 464
ret: 0 ret: 0
status: Ok(()) status: Ok(())