Skip to content

Commit 7d25c0d

Browse files
committed
make assertions against LIR output
1 parent cc87115 commit 7d25c0d

2 files changed

Lines changed: 108 additions & 73 deletions

File tree

zjit/src/backend/arm64/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1750,11 +1750,11 @@ mod tests {
17501750
let val32 = asm.sub(Opnd::Value(Qtrue), Opnd::Imm(1));
17511751
asm.store(Opnd::mem(64, EC, 0x10).with_num_bits(32), val32.with_num_bits(32));
17521752
asm.je(label);
1753+
asm.frame_teardown(JIT_PRESERVED_REGS);
17531754
asm.cret(val64);
17541755

1755-
asm.frame_teardown(JIT_PRESERVED_REGS);
1756-
assert_disasm_snapshot!(lir_string(&mut asm), @r"
1757-
bb0:
1756+
assert_disasm_snapshot!(lir_string(&mut asm), @"
1757+
bb0():
17581758
# bb0(): foo@/tmp/a.rb:1
17591759
FrameSetup 1, x19, x21, x20
17601760
v0 = Add x19, 0x40
@@ -1764,8 +1764,8 @@ mod tests {
17641764
v1 = Sub Value(0x14), Imm(1)
17651765
Store Mem32[x20 + 0x10], VReg32(v1)
17661766
Je bb0
1767-
CRet v0
17681767
FrameTeardown x19, x21, x20
1768+
CRet v0
17691769
");
17701770
}
17711771

zjit/src/backend/lir.rs

Lines changed: 104 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2507,90 +2507,101 @@ impl fmt::Display for Assembler {
25072507
}
25082508
}
25092509

2510-
for insn in self.linearize_instructions().iter() {
2511-
match insn {
2512-
Insn::Comment(comment) => {
2513-
writeln!(f, " {bold_begin}# {comment}{bold_end}")?;
2514-
}
2515-
Insn::Label(target) => {
2516-
let &Target::Label(Label(label_idx)) = target else {
2517-
panic!("unexpected target for Insn::Label: {target:?}");
2518-
};
2519-
writeln!(f, " {}:", label_name(self, label_idx, &label_counts))?;
2520-
}
2521-
_ => {
2522-
write!(f, " ")?;
2523-
2524-
// Print output operand if any
2525-
if let Some(out) = insn.out_opnd() {
2526-
write!(f, "{out} = ")?;
2510+
for block_id in self.rpo() {
2511+
let bb = &self.basic_blocks[block_id.0];
2512+
let params = &bb.parameters;
2513+
for insn in &bb.insns {
2514+
match insn {
2515+
Insn::Comment(comment) => {
2516+
writeln!(f, " {bold_begin}# {comment}{bold_end}")?;
25272517
}
2518+
Insn::Label(target) => {
2519+
let Target::Label(Label(label_idx)) = target else {
2520+
panic!("unexpected target for Insn::Label: {target:?}");
2521+
};
2522+
write!(f, " {}(", label_name(self, *label_idx, &label_counts))?;
2523+
for (idx, param) in params.iter().enumerate() {
2524+
if idx > 0 {
2525+
write!(f, ", ")?;
2526+
}
2527+
write!(f, "{param}")?;
2528+
}
2529+
writeln!(f, "):")?;
2530+
}
2531+
_ => {
2532+
write!(f, " ")?;
2533+
2534+
// Print output operand if any
2535+
if let Some(out) = insn.out_opnd() {
2536+
write!(f, "{out} = ")?;
2537+
}
25282538

2529-
// Print the instruction name
2530-
write!(f, "{}", insn.op())?;
2539+
// Print the instruction name
2540+
write!(f, "{}", insn.op())?;
25312541

2532-
// Show slot_count for FrameSetup
2533-
if let Insn::FrameSetup { slot_count, preserved } = insn {
2534-
write!(f, " {slot_count}")?;
2535-
if !preserved.is_empty() {
2536-
write!(f, ",")?;
2542+
// Show slot_count for FrameSetup
2543+
if let Insn::FrameSetup { slot_count, preserved } = insn {
2544+
write!(f, " {slot_count}")?;
2545+
if !preserved.is_empty() {
2546+
write!(f, ",")?;
2547+
}
25372548
}
2538-
}
25392549

2540-
// Print target
2541-
if let Some(target) = insn.target() {
2542-
match target {
2543-
Target::CodePtr(code_ptr) => write!(f, " {code_ptr:?}")?,
2544-
Target::Label(Label(label_idx)) => write!(f, " {}", label_name(self, *label_idx, &label_counts))?,
2545-
Target::SideExit { reason, .. } => write!(f, " Exit({reason})")?,
2546-
Target::Block(edge) => {
2547-
if edge.args.is_empty() {
2548-
write!(f, " bb{}", edge.target.0)?;
2549-
} else {
2550-
write!(f, " bb{}(", edge.target.0)?;
2551-
for (i, arg) in edge.args.iter().enumerate() {
2552-
if i > 0 {
2553-
write!(f, ", ")?;
2550+
// Print target
2551+
if let Some(target) = insn.target() {
2552+
match target {
2553+
Target::CodePtr(code_ptr) => write!(f, " {code_ptr:?}")?,
2554+
Target::Label(Label(label_idx)) => write!(f, " {}", label_name(self, *label_idx, &label_counts))?,
2555+
Target::SideExit { reason, .. } => write!(f, " Exit({reason})")?,
2556+
Target::Block(edge) => {
2557+
if edge.args.is_empty() {
2558+
write!(f, " bb{}", edge.target.0)?;
2559+
} else {
2560+
write!(f, " bb{}(", edge.target.0)?;
2561+
for (i, arg) in edge.args.iter().enumerate() {
2562+
if i > 0 {
2563+
write!(f, ", ")?;
2564+
}
2565+
write!(f, "{}", arg)?;
25542566
}
2555-
write!(f, "{}", arg)?;
2567+
write!(f, ")")?;
25562568
}
2557-
write!(f, ")")?;
25582569
}
25592570
}
25602571
}
2561-
}
25622572

2563-
// Print list of operands
2564-
if let Some(Target::SideExit { .. }) = insn.target() {
2565-
// If the instruction has a SideExit, avoid using opnd_iter(), which has stack/locals.
2566-
// Here, only handle instructions that have both Opnd and Target.
2567-
match insn {
2568-
Insn::Joz(opnd, _) |
2569-
Insn::Jonz(opnd, _) |
2570-
Insn::LeaJumpTarget { out: opnd, target: _ } => {
2571-
write!(f, ", {opnd}")?;
2573+
// Print list of operands
2574+
if let Some(Target::SideExit { .. }) = insn.target() {
2575+
// If the instruction has a SideExit, avoid using opnd_iter(), which has stack/locals.
2576+
// Here, only handle instructions that have both Opnd and Target.
2577+
match insn {
2578+
Insn::Joz(opnd, _) |
2579+
Insn::Jonz(opnd, _) |
2580+
Insn::LeaJumpTarget { out: opnd, target: _ } => {
2581+
write!(f, ", {opnd}")?;
2582+
}
2583+
_ => {}
25722584
}
2573-
_ => {}
2574-
}
2575-
} else if let Some(Target::Block(_)) = insn.target() {
2576-
// If the instruction has a Block target, avoid using opnd_iter() for branch args
2577-
// since they're already printed inline with the target. Only print non-target operands.
2578-
match insn {
2579-
Insn::Joz(opnd, _) |
2580-
Insn::Jonz(opnd, _) |
2581-
Insn::LeaJumpTarget { out: opnd, target: _ } => {
2582-
write!(f, ", {opnd}")?;
2585+
} else if let Some(Target::Block(_)) = insn.target() {
2586+
// If the instruction has a Block target, avoid using opnd_iter() for branch args
2587+
// since they're already printed inline with the target. Only print non-target operands.
2588+
match insn {
2589+
Insn::Joz(opnd, _) |
2590+
Insn::Jonz(opnd, _) |
2591+
Insn::LeaJumpTarget { out: opnd, target: _ } => {
2592+
write!(f, ", {opnd}")?;
2593+
}
2594+
_ => {}
25832595
}
2584-
_ => {}
2596+
} else if let Insn::ParallelMov { moves } = insn {
2597+
// Print operands with a special syntax for ParallelMov
2598+
moves.iter().try_fold(" ", |prefix, (dst, src)| write!(f, "{prefix}{dst} <- {src}").and(Ok(", ")))?;
2599+
} else if insn.opnd_iter().count() > 0 {
2600+
insn.opnd_iter().try_fold(" ", |prefix, opnd| write!(f, "{prefix}{opnd}").and(Ok(", ")))?;
25852601
}
2586-
} else if let Insn::ParallelMov { moves } = insn {
2587-
// Print operands with a special syntax for ParallelMov
2588-
moves.iter().try_fold(" ", |prefix, (dst, src)| write!(f, "{prefix}{dst} <- {src}").and(Ok(", ")))?;
2589-
} else if insn.opnd_iter().count() > 0 {
2590-
insn.opnd_iter().try_fold(" ", |prefix, opnd| write!(f, "{prefix}{opnd}").and(Ok(", ")))?;
2591-
}
25922602

2593-
write!(f, "\n")?;
2603+
write!(f, "\n")?;
2604+
}
25942605
}
25952606
}
25962607
}
@@ -3206,6 +3217,7 @@ impl Drop for AssemblerPanicHook {
32063217
#[cfg(test)]
32073218
mod tests {
32083219
use super::*;
3220+
use insta::assert_snapshot;
32093221

32103222
fn scratch_reg() -> Opnd {
32113223
Assembler::new_with_scratch_reg().1
@@ -3434,4 +3446,27 @@ mod tests {
34343446
vec![r10.vreg_idx(), r12.vreg_idx()]
34353447
);
34363448
}
3449+
3450+
fn test_lir_debug_output() {
3451+
let TestFunc { asm, .. } = build_func();
3452+
3453+
// Test the LIR string output
3454+
let output = lir_string(&asm);
3455+
3456+
assert_snapshot!(output, @"
3457+
bb0(v0, v1):
3458+
Jmp bb1(1, v1)
3459+
bb1(v2, v3):
3460+
Cmp v3, 1
3461+
Jl bb3
3462+
Jmp bb2
3463+
bb3():
3464+
v6 = Add v0, v2
3465+
CRet v6
3466+
bb2():
3467+
v4 = Mul v2, v3
3468+
v5 = Sub v3, 1
3469+
Jmp bb1(v4, v5)
3470+
");
3471+
}
34373472
}

0 commit comments

Comments
 (0)