From 41b70bec43b315d100edea3bb1520052e0298eac Mon Sep 17 00:00:00 2001 From: Jakub Doka Date: Wed, 23 Oct 2024 12:26:07 +0200 Subject: [PATCH] should work better --- lang/README.md | 12 +- lang/src/fs.rs | 6 + lang/src/main.rs | 2 +- lang/src/son.rs | 205 +++++++++++++----- .../son_tests_exhaustive_loop_testing.txt | 53 ++--- lang/tests/son_tests_inline_test.txt | 26 ++- 6 files changed, 213 insertions(+), 91 deletions(-) diff --git a/lang/README.md b/lang/README.md index a7970a3..ada5cb3 100644 --- a/lang/README.md +++ b/lang/README.md @@ -743,8 +743,8 @@ rect_line := fn(buffer: Buffer, pos: Point, tr: Transform, color: ColorBGRA, thi y = pos.y x = pos.x loop if y == pos.y + tr.x break else { - a := 1 + @inline(screenidx, 10) - a = 1 + @inline(screenidx, 2) + //a := 1 + @inline(screenidx, 10) + //a = 1 + @inline(screenidx, 2) y += 1 } t += 1 @@ -958,7 +958,15 @@ main := fn(): int { return 6 } + f := 0 loop { + if f == 1 { + f = 0 + } else { + f = 1 + } + + f = continue_and_state_change(0) } } diff --git a/lang/src/fs.rs b/lang/src/fs.rs index 4528e90..d022e37 100644 --- a/lang/src/fs.rs +++ b/lang/src/fs.rs @@ -94,6 +94,12 @@ pub fn run_compiler(root_file: &str, options: Options, out: &mut Vec) -> std codegen.push_embeds(parsed.embeds); codegen.generate(0); + + if !codegen.errors.borrow().is_empty() { + log::error!("{}", codegen.errors.borrow()); + return Err(std::io::Error::other("compilation faoled")); + } + if options.dump_asm { codegen .disasm(unsafe { std::mem::transmute::<&mut Vec, &mut String>(out) }) diff --git a/lang/src/main.rs b/lang/src/main.rs index 753cb15..a1f6906 100644 --- a/lang/src/main.rs +++ b/lang/src/main.rs @@ -3,7 +3,7 @@ fn main() -> std::io::Result<()> { use std::io::Write; log::set_logger(&hblang::Logger).unwrap(); - log::set_max_level(log::LevelFilter::Error); + log::set_max_level(log::LevelFilter::Info); let args = std::env::args().collect::>(); let args = args.iter().map(String::as_str).collect::>(); diff --git a/lang/src/son.rs b/lang/src/son.rs index 7d9be76..35509e8 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -27,7 +27,7 @@ use { hashbrown::hash_map, hbbytecode::DisasmError, regalloc2::VReg, - std::{borrow::ToOwned, panic}, + std::borrow::ToOwned, }; const VOID: Nid = 0; @@ -108,39 +108,41 @@ impl Nodes { for (i, node) in self.iter() { let color = match () { - _ if self[i].lock_rc != 0 => "red", - _ if self[i].outputs.is_empty() => "purple", - _ if self[i].is_mem() => "green", + _ if node.lock_rc == Nid::MAX => "orange", + _ if node.lock_rc == Nid::MAX - 1 => "blue", + _ if node.lock_rc != 0 => "red", + _ if node.outputs.is_empty() => "purple", + _ if node.is_mem() => "green", _ if self.is_cfg(i) => "yellow", _ => "white", }; - let mut dest = i; - let mut index_override = None; + let dest = i; + //let mut index_override = None; - if !matches!(node.kind, Kind::Then | Kind::Else) { - if node.ty != ty::Id::VOID { - writeln!( - out, - " node{i}[label=\"{} {}\" color={color}]", - node.kind, - ty::Display::new(tys, files, node.ty) - )?; - } else { - writeln!(out, " node{i}[label=\"{}\" color={color}]", node.kind,)?; - } + //if !matches!(node.kind, Kind::Then | Kind::Else) { + if node.ty != ty::Id::VOID { + writeln!( + out, + " node{i}[label=\"{i} {} {}\" color={color}]", + node.kind, + ty::Display::new(tys, files, node.ty) + )?; } else { - dest = node.inputs[0]; - - index_override = if node.kind == Kind::Then { Some(0) } else { Some(1) }; + writeln!(out, " node{i}[label=\"{i} {}\" color={color}]", node.kind,)?; } + //} else { + // dest = node.inputs[0]; - if node.kind == Kind::If { - continue; - } + // index_override = if node.kind == Kind::Then { Some(0) } else { Some(1) }; + //} + + //if node.kind == Kind::If { + // continue; + //} for (j, &o) in node.outputs.iter().enumerate() { - let j = index_override.unwrap_or(j); + //let j = index_override.unwrap_or(j); let color = if self.is_cfg(i) && self.is_cfg(o) { "red" } else { "lightgray" }; let index = self[o].inputs.iter().position(|&inp| i == inp).unwrap(); let style = if index == 0 && !self.is_cfg(o) { "style=dotted" } else { "" }; @@ -205,6 +207,26 @@ impl Nodes { let node = Node { ralloc_backref: u16::MAX, inputs: inps.into(), kind, ty, ..Default::default() }; + if node.kind == Kind::Phi && node.ty != ty::Id::VOID { + debug_assert_ne!( + self[node.inputs[1]].ty, + ty::Id::VOID, + "{:?} {:?}", + self[node.inputs[1]], + node.ty.expand(), + ); + + if self[node.inputs[0]].kind != Kind::Loop { + debug_assert_ne!( + self[node.inputs[2]].ty, + ty::Id::VOID, + "{:?} {:?}", + self[node.inputs[2]], + node.ty.expand(), + ); + } + } + let mut lookup_meta = None; if !node.is_not_gvnd() { let (raw_entry, hash) = self.lookup.entry(node.key(), &self.values); @@ -857,6 +879,7 @@ impl Nodes { self.values.iter_mut().flat_map(Result::as_mut) } + #[allow(dead_code)] fn eliminate_stack_temporaries(&mut self) { if !cfg!(debug_assertions) { return; @@ -1192,7 +1215,7 @@ mod var { impl Scope { pub fn iter_mut(&mut self) -> impl Iterator { - self.vars.iter_mut().chain(core::iter::once(&mut self.store)) + core::iter::once(&mut self.store).chain(self.vars.iter_mut()) } pub fn dup(&self, nodes: &mut Nodes) -> Self { @@ -1216,8 +1239,9 @@ struct ItemCtx { file: FileId, ret: Option, task_base: usize, + inline_var_base: usize, inline_depth: u16, - inline_ret: Option<(Value, Nid)>, + inline_ret: Option<(Value, Nid, Scope)>, nodes: Nodes, ctrl: Nid, call_count: u16, @@ -1290,6 +1314,10 @@ impl ItemCtx { }; regalloc2::run_with_ctx(&fuc, &ralloc.env, &options, &mut ralloc.ctx).unwrap_or_else( |err| { + if let regalloc2::RegAllocError::SSA(vreg, inst) = err { + fuc.nodes[vreg.vreg() as Nid].lock_rc = Nid::MAX; + fuc.nodes[fuc.instrs[inst.index()].nid].lock_rc = Nid::MAX - 1; + } fuc.nodes.graphviz_in_browser(tys, files); panic!("{err}") }, @@ -1794,7 +1822,7 @@ pub struct Codegen<'a> { #[expect(dead_code)] ralloc: Regalloc, ct: Comptime, - errors: RefCell, + pub errors: RefCell, } impl TypeParser for Codegen<'_> { @@ -2018,8 +2046,16 @@ impl<'a> Codegen<'a> { fn load_mem(&mut self, region: Nid, ty: ty::Id) -> Nid { debug_assert_ne!(region, VOID); + debug_assert_ne!({ self.ci.nodes[region].ty }, ty::Id::VOID, "{:?}", { + self.ci.nodes[region].lock_rc = Nid::MAX; + self.ci.nodes.graphviz_in_browser(&self.tys, self.files); + }); debug_assert!( - self.ci.nodes[region].kind != Kind::Load || self.ci.nodes[region].ty.is_pointer() + self.ci.nodes[region].kind != Kind::Load || self.ci.nodes[region].ty.is_pointer(), + "{:?} {} {}", + self.ci.nodes.graphviz_in_browser(&self.tys, self.files), + self.cfile().path, + self.ty_display(self.ci.nodes[region].ty) ); debug_assert!(self.ci.nodes[region].kind != Kind::Stre); let mut vc = Vc::from([VOID, region]); @@ -2095,7 +2131,7 @@ impl<'a> Codegen<'a> { if let Some(index) = self.ci.scope.vars.iter().rposition(|v| v.id == id) => { let var = &mut self.ci.scope.vars[index]; - self.ci.nodes.load_loop_var(index, var, &mut self.ci.loops); + self.ci.nodes.load_loop_var(index + 1, var, &mut self.ci.loops); Some(Value::var(index).ty(var.ty)) } @@ -2108,10 +2144,7 @@ impl<'a> Codegen<'a> { let value = self.ci.nodes.new_node(gl.ty, Kind::Global { global }, [VOID]); Some(Value::ptr(value).ty(gl.ty)) } - _ => self.report_unhandled_ast( - expr, - format_args!("identifier evaluated to '{}'", self.ty_display(decl)), - ), + _ => Some(Value::new(Nid::MAX).ty(decl)), } } Expr::Comment { .. } => Some(Value::VOID), @@ -2152,19 +2185,31 @@ impl<'a> Codegen<'a> { self.ci.nodes[NEVER].inputs.push(self.ci.ctrl); self.ci.nodes[self.ci.ctrl].outputs.push(NEVER); - } else if let Some((pv, ctrl)) = &mut self.ci.inline_ret { + } else if let Some((pv, ctrl, scope)) = &mut self.ci.inline_ret { self.ci.nodes.unlock(*ctrl); *ctrl = self.ci.nodes.new_node(ty::Id::VOID, Kind::Region, [self.ci.ctrl, *ctrl]); self.ci.nodes.lock(*ctrl); - self.ci.ctrl = *ctrl; + Self::merge_scopes( + &mut self.ci.nodes, + &mut self.ci.loops, + *ctrl, + scope, + &mut self.ci.scope, + ); 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); + self.ci.ctrl = *ctrl; } else { self.ci.nodes.lock(value.id); self.ci.nodes.lock(self.ci.ctrl); - self.ci.inline_ret = Some((value, self.ci.ctrl)); + let mut scope = self.ci.scope.dup(&mut self.ci.nodes); + scope + .vars + .drain(self.ci.inline_var_base..) + .for_each(|v| v.remove(&mut self.ci.nodes)); + self.ci.inline_ret = Some((value, self.ci.ctrl, scope)); } None @@ -2174,6 +2219,19 @@ impl<'a> Codegen<'a> { self.strip_var(&mut vtarget); let tty = vtarget.ty; + if let ty::Kind::Module(m) = tty.expand() { + return match self.find_type(pos, m, Err(name), self.files).expand() { + ty::Kind::Builtin(ty::NEVER) => Value::NEVER, + ty::Kind::Global(global) => { + let gl = &self.tys.ins.globals[global as usize]; + let value = + self.ci.nodes.new_node(gl.ty, Kind::Global { global }, [VOID]); + Some(Value::ptr(value).ty(gl.ty)) + } + v => Some(Value::new(Nid::MAX).ty(v.compress())), + }; + } + let ty::Kind::Struct(s) = self.tys.base_of(tty).unwrap_or(tty).expand() else { self.report( pos, @@ -2296,7 +2354,7 @@ impl<'a> Codegen<'a> { self.ci.nodes.unlock(lhs.id); let mut rhs = rhs?; self.strip_var(&mut rhs); - let ty = self.binop_ty(left.pos(), &mut rhs, &mut lhs, op); + let ty = self.binop_ty(left.pos(), &mut lhs, &mut rhs, op); let inps = [VOID, lhs.id, rhs.id]; Some(self.ci.nodes.new_node_lit( ty::bin_ret(ty, op), @@ -2463,7 +2521,7 @@ impl<'a> Codegen<'a> { return Value::NEVER; }; - let mut inps = Vc::from([self.ci.ctrl]); + let mut inps = Vc::from([NEVER]); for arg in args { let value = self.expr(arg)?; debug_assert_ne!(self.ci.nodes[value.id].kind, Kind::Stre); @@ -2500,6 +2558,7 @@ impl<'a> Codegen<'a> { }; let argc = args.len() as u32; + inps[0] = self.ci.ctrl; self.ci.ctrl = self.ci.nodes.new_node(ty, Kind::Call { func: ty::ECA, argc }, inps); self.store_mem(VOID, VOID); @@ -2538,7 +2597,7 @@ impl<'a> Codegen<'a> { ); } - let mut inps = Vc::from([self.ci.ctrl]); + let mut inps = Vc::from([NEVER]); let mut tys = sig.args.range(); for (arg, carg) in args.iter().zip(cargs) { let ty = self.tys.ins.args[tys.next().unwrap()]; @@ -2546,6 +2605,7 @@ impl<'a> Codegen<'a> { tys.next().unwrap(); continue; } + std::println!("{}", self.ast_display(arg)); let mut value = self.expr_ctx(arg, Ctx::default().with_ty(ty))?; debug_assert_ne!(self.ci.nodes[value.id].kind, Kind::Stre); self.assert_ty(arg.pos(), &mut value, ty, fa!("argument {}", carg.name)); @@ -2583,6 +2643,7 @@ impl<'a> Codegen<'a> { } }; + inps[0] = self.ci.ctrl; self.ci.ctrl = self.ci.nodes.new_node(sig.ret, Kind::Call { func: fu, argc }, inps); self.store_mem(VOID, VOID); @@ -2626,7 +2687,8 @@ impl<'a> Codegen<'a> { ); } - let arg_base = self.ci.scope.vars.len(); + let prev_var_base = + std::mem::replace(&mut self.ci.inline_var_base, self.ci.scope.vars.len()); let mut sig_args = sig.args.range(); for (arg, carg) in args.iter().zip(cargs) { let ty = self.tys.ins.args[sig_args.next().unwrap()]; @@ -2641,7 +2703,8 @@ impl<'a> Codegen<'a> { continue; } - let mut value = self.expr_ctx(arg, Ctx::default().with_ty(ty))?; + let mut value = self.raw_expr_ctx(arg, Ctx::default().with_ty(ty))?; + self.strip_var(&mut value); 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)); @@ -2671,15 +2734,22 @@ impl<'a> Codegen<'a> { self.ci.ret = prev_ret; self.ci.file = prev_file; self.ci.inline_depth -= 1; - for var in self.ci.scope.vars.drain(arg_base..) { + for var in self.ci.scope.vars.drain(self.ci.inline_var_base..) { var.remove(&mut self.ci.nodes); } + self.ci.inline_var_base = prev_var_base; - core::mem::replace(&mut self.ci.inline_ret, prev_inline_ret).map(|(v, ctrl)| { - self.ci.nodes.unlock(ctrl); - self.ci.nodes.unlock(v.id); - v - }) + core::mem::replace(&mut self.ci.inline_ret, prev_inline_ret).map( + |(v, ctrl, scope)| { + self.ci.nodes.unlock(ctrl); + self.ci.nodes.unlock(v.id); + self.ci.scope.clear(&mut self.ci.nodes); + self.ci.scope = scope; + std::println!("{:?}", self.ci.nodes[ctrl]); + self.ci.ctrl = ctrl; + v + }, + ) } Expr::Tupl { pos, ty, fields, .. } => { let Some(sty) = ty.map(|ty| self.ty(ty)).or(ctx.ty) else { @@ -2912,8 +2982,27 @@ impl<'a> Codegen<'a> { } if bre == Nid::MAX { - self.ci.ctrl = NEVER; + for (loop_var, scope_var) in self.ci.scope.iter_mut().zip(scope.iter_mut()) { + if self.ci.nodes[scope_var.value()].is_lazy_phi(node) { + if loop_var.value() != scope_var.value() { + scope_var.set_value( + self.ci.nodes.modify_input( + scope_var.value(), + 2, + loop_var.value(), + ), + &mut self.ci.nodes, + ); + } else { + let phi = &self.ci.nodes[scope_var.value()]; + let prev = phi.inputs[1]; + self.ci.nodes.replace(scope_var.value(), prev); + scope_var.set_value(prev, &mut self.ci.nodes); + } + } + } scope.clear(&mut self.ci.nodes); + self.ci.ctrl = NEVER; return None; } self.ci.ctrl = bre; @@ -2954,6 +3043,7 @@ impl<'a> Codegen<'a> { scope.clear(&mut self.ci.nodes); bres.clear(&mut self.ci.nodes); + self.ci.scope.loads.drain(..).for_each(|l| _ = self.ci.nodes.unlock_remove(l)); self.ci.nodes.unlock(self.ci.ctrl); self.ci.nodes.unlock(node); @@ -3253,6 +3343,7 @@ impl<'a> Codegen<'a> { ) { nodes.lock(ctrl); for (i, (to_value, from_value)) in to.iter_mut().zip(from.iter_mut()).enumerate() { + debug_assert_eq!(to_value.ty, from_value.ty); if to_value.value() != from_value.value() { nodes.load_loop_var(i, from_value, loops); nodes.load_loop_var(i, to_value, loops); @@ -3298,6 +3389,8 @@ impl<'a> Codegen<'a> { self.pool.push_ci(file, Some(sig.ret), 0, &mut self.ci); + log::info!("emmiting {}", self.ast_display(expr)); + let &Expr::Closure { body, args, .. } = expr else { unreachable!("{}", self.ast_display(expr)) }; @@ -3546,6 +3639,9 @@ impl<'a> Function<'a> { "{:?}", self.nodes[nid] ); + debug_assert_eq!(self.nodes[nid].lock_rc, 0, "{:?}", self.nodes[nid]); + debug_assert_ne!(nid, MEM); + debug_assert!(self.nodes[nid].kind != Kind::Phi || self.nodes[nid].ty != ty::Id::VOID); regalloc2::VReg::new(nid as _, regalloc2::RegClass::Int) } @@ -3754,13 +3850,13 @@ impl<'a> Function<'a> { let ty = self.nodes[i].ty; match parama.next(ty, self.tys) { PLoc::None => {} - PLoc::Reg(r, _) => { + PLoc::Reg(r, _) if ty.loc(self.tys) == Loc::Reg => { ops.push(regalloc2::Operand::reg_fixed_use( self.rg(i), regalloc2::PReg::new(r as _, regalloc2::RegClass::Int), )); } - PLoc::WideReg(..) => { + PLoc::WideReg(..) | PLoc::Reg(..) => { loop { match self.nodes[i].kind { Kind::Stre { .. } => i = self.nodes[i].inputs[2], @@ -3774,6 +3870,7 @@ impl<'a> Function<'a> { } PLoc::Ref(r, _) => { loop { + std::println!("{:?} {}", self.nodes[i], i); match self.nodes[i].kind { Kind::Stre { .. } => i = self.nodes[i].inputs[2], Kind::Load { .. } => i = self.nodes[i].inputs[1], @@ -3860,7 +3957,11 @@ impl<'a> Function<'a> { } let ops = match self.nodes[region].kind { _ if node.ty.loc(self.tys) == Loc::Stack => { - vec![self.urg(region), self.urg(self.nodes[node.inputs[1]].inputs[1])] + if self.nodes[node.inputs[1]].kind == Kind::Arg { + vec![self.urg(region), self.urg(node.inputs[1])] + } else { + vec![self.urg(region), self.urg(self.nodes[node.inputs[1]].inputs[1])] + } } Kind::Stck => vec![self.urg(node.inputs[1])], _ => vec![self.urg(region), self.urg(node.inputs[1])], @@ -4222,7 +4323,7 @@ mod tests { fn generate(ident: &'static str, input: &'static str, output: &mut String) { _ = log::set_logger(&crate::fs::Logger); - //log::set_max_level(log::LevelFilter::Info); + log::set_max_level(log::LevelFilter::Info); // log::set_max_level(log::LevelFilter::Trace); let (ref files, embeds) = crate::test_parse_files(ident, input); diff --git a/lang/tests/son_tests_exhaustive_loop_testing.txt b/lang/tests/son_tests_exhaustive_loop_testing.txt index 0171cdb..62d7740 100644 --- a/lang/tests/son_tests_exhaustive_loop_testing.txt +++ b/lang/tests/son_tests_exhaustive_loop_testing.txt @@ -21,47 +21,49 @@ main: LI64 r32, 0d CP r2, r32 JAL r31, r0, :multiple_breaks - CP r33, r32 - CP r34, r1 + CP r33, r1 LI64 r1, 3d - JEQ r34, r1, :0 - LI64 r1, 1d + LI64 r34, 1d + JEQ r33, r1, :0 + CP r1, r34 JMP :1 0: CP r35, r1 - LI64 r36, 4d - CP r2, r36 + CP r36, r34 + LI64 r37, 4d + CP r2, r37 JAL r31, r0, :multiple_breaks - CP r37, r36 - LI64 r38, 10d - JEQ r1, r38, :2 + CP r38, r37 + LI64 r39, 10d + JEQ r1, r39, :2 LI64 r1, 2d JMP :1 - 2: CP r2, r33 + 2: CP r2, r32 JAL r31, r0, :state_change_in_break - CP r39, r1 - CP r1, r33 - JEQ r39, r1, :3 + JEQ r1, r32, :3 CP r1, r35 JMP :1 - 3: CP r33, r1 - CP r2, r37 + 3: CP r2, r38 JAL r31, r0, :state_change_in_break - JEQ r1, r38, :4 - CP r1, r37 + JEQ r1, r39, :4 + CP r1, r38 JMP :1 - 4: CP r2, r38 + 4: CP r2, r39 JAL r31, r0, :continue_and_state_change - JEQ r1, r38, :5 + JEQ r1, r39, :5 LI64 r1, 5d JMP :1 5: CP r2, r35 JAL r31, r0, :continue_and_state_change - CP r40, r1 - CP r1, r33 - JEQ r40, r1, :6 + JEQ r1, r32, :6 LI64 r1, 6d JMP :1 - 6: CP r1, r33 + 6: CP r1, r32 + CP r40, r36 + 8: JNE r1, r40, :7 + JMP :7 + 7: CP r2, r32 + JAL r31, r0, :continue_and_state_change + JMP :8 1: LD r31, r254, 0a, 80h ADDI64 r254, r254, 80d JALA r0, r31, 0a @@ -89,6 +91,7 @@ state_change_in_break: 2: ADDI64 r2, r2, 1d JMP :4 3: JALA r0, r31, 0a -code size: 569 -ret: 0 +timed out +code size: 585 +ret: 10 status: Ok(()) diff --git a/lang/tests/son_tests_inline_test.txt b/lang/tests/son_tests_inline_test.txt index 2a62ae6..85453b0 100644 --- a/lang/tests/son_tests_inline_test.txt +++ b/lang/tests/son_tests_inline_test.txt @@ -18,17 +18,19 @@ integer: 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 + ADDI64 r254, r254, -48d + ST r2, r254, 32a, 16h + ADDI64 r2, r254, 32d + ST r4, r254, 16a, 16h + ADDI64 r4, r254, 16d ST r6, r254, 0a, 16h ADDI64 r6, r254, 0d LD r9, r4, 0a, 8h LD r11, r2, 0a, 8h JGTS r11, r9, :0 JMP :0 - 0: JALA r0, r31, 0a + 0: ADDI64 r254, r254, 48d + JALA r0, r31, 0a main: ADDI64 r254, r254, -184d ST r31, r254, 96a, 88h @@ -70,10 +72,11 @@ main: ADDI64 r254, r254, 184d JALA r0, r31, 0a rect_line: - ST r2, r254, 0a, 16h - ADDI64 r2, r254, 0d - ST r4, r254, 0a, 16h - ADDI64 r4, r254, 0d + ADDI64 r254, r254, -48d + ST r2, r254, 32a, 16h + ADDI64 r2, r254, 32d + ST r4, r254, 16a, 16h + ADDI64 r4, r254, 16d ST r6, r254, 0a, 16h ADDI64 r6, r254, 0d LI64 r10, 0d @@ -88,7 +91,8 @@ rect_line: JMP :3 2: ADDI64 r9, r9, 1d JMP :4 - 1: JALA r0, r31, 0a -code size: 886 + 1: ADDI64 r254, r254, 48d + JALA r0, r31, 0a +code size: 930 ret: 0 status: Ok(())