From 441a826e20023958af7799e03dd3aafc657fdf32 Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Tue, 4 Aug 2026 18:52:33 +0200 Subject: [PATCH] perf: cranelift: codegen: optimize RawInst print using RawInstDisplay, RegNameDisplay --- cranelift/codegen/meta/src/pulley.rs | 34 ++-- .../src/isa/pulley_shared/inst/args.rs | 146 ++++++++++++------ .../codegen/src/isa/pulley_shared/inst/mod.rs | 85 +++++----- 3 files changed, 171 insertions(+), 94 deletions(-) diff --git a/cranelift/codegen/meta/src/pulley.rs b/cranelift/codegen/meta/src/pulley.rs index 77e760eda7a3..4af01ae3ceea 100644 --- a/cranelift/codegen/meta/src/pulley.rs +++ b/cranelift/codegen/meta/src/pulley.rs @@ -103,11 +103,11 @@ impl Inst<'_> { } } -pub fn generate_rust(filename: &str, out_dir: &Path) -> Result<(), Error> { - let mut rust = String::new(); - - // Generate a pretty-printing method for debugging. - rust.push_str("pub fn print(inst: &RawInst) -> String {\n"); +/// Generates a pretty-printing method for debugging. +pub fn generate_raw_inst_display(rust: &mut String) -> Result<(), Error> { + rust.push_str("impl<'a> std::fmt::Display for RawInstDisplay<'a> {\n"); + rust.push_str("fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n"); + rust.push_str("let inst = self.0;\n"); rust.push_str("match inst {\n"); for inst @ Inst { name, .. } in OPS.iter().chain(EXTENDED_OPS) { if inst.skip() { @@ -140,9 +140,11 @@ pub fn generate_rust(filename: &str, out_dir: &Path) -> Result<(), Error> { format_string.push_str("}"); if ty.contains("Reg") { if matches!(op, Operand::Writable { .. }) { - locals.push_str(&format!("let {name} = reg_name(*{name}.to_reg());\n")); + locals.push_str(&format!( + "let {name} = RegNameDisplay(*{name}.to_reg());\n" + )); } else { - locals.push_str(&format!("let {name} = reg_name(**{name});\n")); + locals.push_str(&format!("let {name} = RegNameDisplay(**{name});\n")); } } } @@ -154,10 +156,10 @@ pub fn generate_rust(filename: &str, out_dir: &Path) -> Result<(), Error> { Operand::Binop { src2, .. } => { pat.push_str("dst, src1, src2,"); format_string.push_str(" {dst}, {src1}, {src2}"); - locals.push_str(&format!("let dst = reg_name(*dst.to_reg());\n")); - locals.push_str(&format!("let src1 = reg_name(**src1);\n")); + locals.push_str(&format!("let dst = RegNameDisplay(*dst.to_reg());\n")); + locals.push_str(&format!("let src1 = RegNameDisplay(**src1);\n")); if src2.contains("Reg") { - locals.push_str(&format!("let src2 = reg_name(**src2);\n")); + locals.push_str(&format!("let src2 = RegNameDisplay(**src2);\n")); } } } @@ -167,13 +169,23 @@ pub fn generate_rust(filename: &str, out_dir: &Path) -> Result<(), Error> { " RawInst::{name} {{ {pat} }} => {{ {locals} - format!(\"{format_string}\") + write!(f, \"{format_string}\") }} " )); } rust.push_str("}\n"); rust.push_str("}\n"); + rust.push_str("}\n"); + + Ok(()) +} + +pub fn generate_rust(filename: &str, out_dir: &Path) -> Result<(), Error> { + let mut rust = String::new(); + + // Generate a pretty-printing method for debugging. + generate_raw_inst_display(&mut rust)?; // Generate `get_operands` to feed information to regalloc rust.push_str( diff --git a/cranelift/codegen/src/isa/pulley_shared/inst/args.rs b/cranelift/codegen/src/isa/pulley_shared/inst/args.rs index e97e3303ef99..7a9351a80df9 100644 --- a/cranelift/codegen/src/isa/pulley_shared/inst/args.rs +++ b/cranelift/codegen/src/isa/pulley_shared/inst/args.rs @@ -204,7 +204,7 @@ impl core::fmt::Display for Amode { } } Amode::RegOffset { base, offset } => { - let name = reg_name(**base); + let name = RegNameDisplay(**base); if *offset >= 0 { write!(f, "{name}+{offset}") } else { @@ -463,103 +463,163 @@ impl Cond { impl fmt::Display for Cond { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Cond::If32 { reg } => write!(f, "if32 {}", reg_name(**reg)), - Cond::IfNot32 { reg } => write!(f, "if_not32 {}", reg_name(**reg)), + Cond::If32 { reg } => write!(f, "if32 {}", RegNameDisplay(**reg)), + Cond::IfNot32 { reg } => write!(f, "if_not32 {}", RegNameDisplay(**reg)), Cond::IfXeq32 { src1, src2 } => { - write!(f, "if_xeq32 {}, {}", reg_name(**src1), reg_name(**src2)) + write!( + f, + "if_xeq32 {}, {}", + RegNameDisplay(**src1), + RegNameDisplay(**src2) + ) } Cond::IfXneq32 { src1, src2 } => { - write!(f, "if_xneq32 {}, {}", reg_name(**src1), reg_name(**src2)) + write!( + f, + "if_xneq32 {}, {}", + RegNameDisplay(**src1), + RegNameDisplay(**src2) + ) } Cond::IfXslt32 { src1, src2 } => { - write!(f, "if_xslt32 {}, {}", reg_name(**src1), reg_name(**src2)) + write!( + f, + "if_xslt32 {}, {}", + RegNameDisplay(**src1), + RegNameDisplay(**src2) + ) } Cond::IfXslteq32 { src1, src2 } => { - write!(f, "if_xslteq32 {}, {}", reg_name(**src1), reg_name(**src2)) + write!( + f, + "if_xslteq32 {}, {}", + RegNameDisplay(**src1), + RegNameDisplay(**src2) + ) } Cond::IfXult32 { src1, src2 } => { - write!(f, "if_xult32 {}, {}", reg_name(**src1), reg_name(**src2)) + write!( + f, + "if_xult32 {}, {}", + RegNameDisplay(**src1), + RegNameDisplay(**src2) + ) } Cond::IfXulteq32 { src1, src2 } => { - write!(f, "if_xulteq32 {}, {}", reg_name(**src1), reg_name(**src2)) + write!( + f, + "if_xulteq32 {}, {}", + RegNameDisplay(**src1), + RegNameDisplay(**src2) + ) } Cond::IfXeq64 { src1, src2 } => { - write!(f, "if_xeq64 {}, {}", reg_name(**src1), reg_name(**src2)) + write!( + f, + "if_xeq64 {}, {}", + RegNameDisplay(**src1), + RegNameDisplay(**src2) + ) } Cond::IfXneq64 { src1, src2 } => { - write!(f, "if_xneq64 {}, {}", reg_name(**src1), reg_name(**src2)) + write!( + f, + "if_xneq64 {}, {}", + RegNameDisplay(**src1), + RegNameDisplay(**src2) + ) } Cond::IfXslt64 { src1, src2 } => { - write!(f, "if_xslt64 {}, {}", reg_name(**src1), reg_name(**src2)) + write!( + f, + "if_xslt64 {}, {}", + RegNameDisplay(**src1), + RegNameDisplay(**src2) + ) } Cond::IfXslteq64 { src1, src2 } => { - write!(f, "if_xslteq64 {}, {}", reg_name(**src1), reg_name(**src2)) + write!( + f, + "if_xslteq64 {}, {}", + RegNameDisplay(**src1), + RegNameDisplay(**src2) + ) } Cond::IfXult64 { src1, src2 } => { - write!(f, "if_xult64 {}, {}", reg_name(**src1), reg_name(**src2)) + write!( + f, + "if_xult64 {}, {}", + RegNameDisplay(**src1), + RegNameDisplay(**src2) + ) } Cond::IfXulteq64 { src1, src2 } => { - write!(f, "if_xulteq64 {}, {}", reg_name(**src1), reg_name(**src2)) + write!( + f, + "if_xulteq64 {}, {}", + RegNameDisplay(**src1), + RegNameDisplay(**src2) + ) } Cond::IfXeq32I32 { src1, src2 } => { - write!(f, "if_xeq32_i32 {}, {src2}", reg_name(**src1)) + write!(f, "if_xeq32_i32 {}, {src2}", RegNameDisplay(**src1)) } Cond::IfXneq32I32 { src1, src2 } => { - write!(f, "if_xneq32_i32 {}, {src2}", reg_name(**src1)) + write!(f, "if_xneq32_i32 {}, {src2}", RegNameDisplay(**src1)) } Cond::IfXslt32I32 { src1, src2 } => { - write!(f, "if_xslt32_i32 {}, {src2}", reg_name(**src1)) + write!(f, "if_xslt32_i32 {}, {src2}", RegNameDisplay(**src1)) } Cond::IfXslteq32I32 { src1, src2 } => { - write!(f, "if_xslteq32_i32 {}, {src2}", reg_name(**src1)) + write!(f, "if_xslteq32_i32 {}, {src2}", RegNameDisplay(**src1)) } Cond::IfXsgt32I32 { src1, src2 } => { - write!(f, "if_xsgt32_i32 {}, {src2}", reg_name(**src1)) + write!(f, "if_xsgt32_i32 {}, {src2}", RegNameDisplay(**src1)) } Cond::IfXsgteq32I32 { src1, src2 } => { - write!(f, "if_xsgteq32_i32 {}, {src2}", reg_name(**src1)) + write!(f, "if_xsgteq32_i32 {}, {src2}", RegNameDisplay(**src1)) } Cond::IfXult32I32 { src1, src2 } => { - write!(f, "if_xult32_i32 {}, {src2}", reg_name(**src1)) + write!(f, "if_xult32_i32 {}, {src2}", RegNameDisplay(**src1)) } Cond::IfXulteq32I32 { src1, src2 } => { - write!(f, "if_xulteq32_i32 {}, {src2}", reg_name(**src1)) + write!(f, "if_xulteq32_i32 {}, {src2}", RegNameDisplay(**src1)) } Cond::IfXugt32I32 { src1, src2 } => { - write!(f, "if_xugt32_i32 {}, {src2}", reg_name(**src1)) + write!(f, "if_xugt32_i32 {}, {src2}", RegNameDisplay(**src1)) } Cond::IfXugteq32I32 { src1, src2 } => { - write!(f, "if_xugteq32_i32 {}, {src2}", reg_name(**src1)) + write!(f, "if_xugteq32_i32 {}, {src2}", RegNameDisplay(**src1)) } Cond::IfXeq64I32 { src1, src2 } => { - write!(f, "if_xeq64_i32 {}, {src2}", reg_name(**src1)) + write!(f, "if_xeq64_i32 {}, {src2}", RegNameDisplay(**src1)) } Cond::IfXneq64I32 { src1, src2 } => { - write!(f, "if_xneq64_i32 {}, {src2}", reg_name(**src1)) + write!(f, "if_xneq64_i32 {}, {src2}", RegNameDisplay(**src1)) } Cond::IfXslt64I32 { src1, src2 } => { - write!(f, "if_xslt64_i32 {}, {src2}", reg_name(**src1)) + write!(f, "if_xslt64_i32 {}, {src2}", RegNameDisplay(**src1)) } Cond::IfXslteq64I32 { src1, src2 } => { - write!(f, "if_xslteq64_i32 {}, {src2}", reg_name(**src1)) + write!(f, "if_xslteq64_i32 {}, {src2}", RegNameDisplay(**src1)) } Cond::IfXsgt64I32 { src1, src2 } => { - write!(f, "if_xsgt64_i32 {}, {src2}", reg_name(**src1)) + write!(f, "if_xsgt64_i32 {}, {src2}", RegNameDisplay(**src1)) } Cond::IfXsgteq64I32 { src1, src2 } => { - write!(f, "if_xsgteq64_i32 {}, {src2}", reg_name(**src1)) + write!(f, "if_xsgteq64_i32 {}, {src2}", RegNameDisplay(**src1)) } Cond::IfXult64I32 { src1, src2 } => { - write!(f, "if_xult64_i32 {}, {src2}", reg_name(**src1)) + write!(f, "if_xult64_i32 {}, {src2}", RegNameDisplay(**src1)) } Cond::IfXulteq64I32 { src1, src2 } => { - write!(f, "if_xulteq64_i32 {}, {src2}", reg_name(**src1)) + write!(f, "if_xulteq64_i32 {}, {src2}", RegNameDisplay(**src1)) } Cond::IfXugt64I32 { src1, src2 } => { - write!(f, "if_xugt64_i32 {}, {src2}", reg_name(**src1)) + write!(f, "if_xugt64_i32 {}, {src2}", RegNameDisplay(**src1)) } Cond::IfXugteq64I32 { src1, src2 } => { - write!(f, "if_xugteq64_i32 {}, {src2}", reg_name(**src1)) + write!(f, "if_xugteq64_i32 {}, {src2}", RegNameDisplay(**src1)) } } } @@ -607,7 +667,7 @@ impl fmt::Display for AddrO32 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { AddrO32::Base { addr, offset } => { - let addr = reg_name(**addr); + let addr = RegNameDisplay(**addr); write!(f, "{addr}, {offset}") } } @@ -644,7 +704,7 @@ impl fmt::Display for AddrZ { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { AddrZ::Base { addr, offset } => { - let addr = reg_name(**addr); + let addr = RegNameDisplay(**addr); write!(f, "{addr}, {offset}") } } @@ -700,9 +760,9 @@ impl fmt::Display for AddrG32 { wasm_addr, offset, } => { - let host_heap_base = reg_name(**host_heap_base); - let host_heap_bound = reg_name(**host_heap_bound); - let wasm_addr = reg_name(**wasm_addr); + let host_heap_base = RegNameDisplay(**host_heap_base); + let host_heap_bound = RegNameDisplay(**host_heap_bound); + let wasm_addr = RegNameDisplay(**wasm_addr); write!( f, "{host_heap_base}, {host_heap_bound}, {wasm_addr}, {offset}", @@ -765,9 +825,9 @@ impl fmt::Display for AddrG32Bne { wasm_addr, offset, } => { - let host_heap_base = reg_name(**host_heap_base); - let host_heap_bound_addr = reg_name(**host_heap_bound_addr); - let wasm_addr = reg_name(**wasm_addr); + let host_heap_base = RegNameDisplay(**host_heap_base); + let host_heap_bound_addr = RegNameDisplay(**host_heap_bound_addr); + let wasm_addr = RegNameDisplay(**wasm_addr); write!( f, "{host_heap_base}, \ diff --git a/cranelift/codegen/src/isa/pulley_shared/inst/mod.rs b/cranelift/codegen/src/isa/pulley_shared/inst/mod.rs index df920f9bcebf..ae5d599faec7 100644 --- a/cranelift/codegen/src/isa/pulley_shared/inst/mod.rs +++ b/cranelift/codegen/src/isa/pulley_shared/inst/mod.rs @@ -40,6 +40,8 @@ mod generated { use super::*; use crate::isa::pulley_shared::lower::isle::generated_code::RawInst; + pub struct RawInstDisplay<'a>(pub &'a RawInst); + include!(concat!(env!("OUT_DIR"), "/pulley_inst_gen.rs")); } @@ -623,24 +625,29 @@ fn test_trap_encoding() { //============================================================================= // Pretty-printing of instructions. -pub fn reg_name(reg: Reg) -> String { - match reg.to_real_reg() { - Some(real) => { - let n = real.hw_enc(); - match (real.class(), n) { - (RegClass::Int, 63) => format!("sp"), - (RegClass::Int, 62) => format!("lr"), - (RegClass::Int, 61) => format!("fp"), - (RegClass::Int, 60) => format!("tmp0"), - (RegClass::Int, 59) => format!("tmp1"), - - (RegClass::Int, _) => format!("x{n}"), - (RegClass::Float, _) => format!("f{n}"), - (RegClass::Vector, _) => format!("v{n}"), +pub struct RegNameDisplay(Reg); + +impl std::fmt::Display for RegNameDisplay { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let reg = self.0; + match reg.to_real_reg() { + Some(real) => { + let n = real.hw_enc(); + match (real.class(), n) { + (RegClass::Int, 63) => f.write_str("sp"), + (RegClass::Int, 62) => f.write_str("lr"), + (RegClass::Int, 61) => f.write_str("fp"), + (RegClass::Int, 60) => f.write_str("tmp0"), + (RegClass::Int, 59) => f.write_str("tmp1"), + + (RegClass::Int, _) => write!(f, "x{n}"), + (RegClass::Float, _) => write!(f, "f{n}"), + (RegClass::Vector, _) => write!(f, "v{n}"), + } + } + None => { + write!(f, "{reg:?}") } - } - None => { - format!("{reg:?}") } } } @@ -660,14 +667,12 @@ impl Inst { { use core::fmt::Write; - let format_reg = |reg: Reg| -> String { reg_name(reg) }; - match self { Inst::Args { args } => { let mut s = "args".to_string(); for arg in args { - let preg = format_reg(arg.preg); - let def = format_reg(arg.vreg.to_reg()); + let preg = RegNameDisplay(arg.preg); + let def = RegNameDisplay(arg.vreg.to_reg()); write!(&mut s, " {def}={preg}").unwrap(); } s @@ -675,15 +680,15 @@ impl Inst { Inst::Rets { rets } => { let mut s = "rets".to_string(); for ret in rets { - let preg = format_reg(ret.preg); - let vreg = format_reg(ret.vreg); + let preg = RegNameDisplay(ret.preg); + let vreg = RegNameDisplay(ret.vreg); write!(&mut s, " {vreg}={preg}").unwrap(); } s } Inst::DummyUse { reg } => { - let reg = format_reg(*reg); + let reg = RegNameDisplay(*reg); format!("dummy_use {reg}") } @@ -694,18 +699,18 @@ impl Inst { Inst::Nop => format!("nop"), Inst::GetSpecial { dst, reg } => { - let dst = format_reg(*dst.to_reg()); - let reg = format_reg(**reg); + let dst = RegNameDisplay(*dst.to_reg()); + let reg = RegNameDisplay(**reg); format!("xmov {dst}, {reg}") } Inst::LoadExtNameNear { dst, name, offset } => { - let dst = format_reg(*dst.to_reg()); + let dst = RegNameDisplay(*dst.to_reg()); format!("{dst} = load_ext_name_near {name:?}, {offset}") } Inst::LoadExtNameFar { dst, name, offset } => { - let dst = format_reg(*dst.to_reg()); + let dst = RegNameDisplay(*dst.to_reg()); format!("{dst} = load_ext_name_far {name:?}, {offset}") } @@ -719,7 +724,7 @@ impl Inst { } Inst::IndirectCall { info } => { - let callee = format_reg(*info.dest); + let callee = RegNameDisplay(*info.dest); let try_call = info .try_call_info .as_ref() @@ -733,7 +738,7 @@ impl Inst { } Inst::ReturnIndirectCall { info } => { - let callee = format_reg(*info.dest); + let callee = RegNameDisplay(*info.dest); format!("return_indirect_call {callee}, {info:?}") } @@ -759,7 +764,7 @@ impl Inst { } Inst::LoadAddr { dst, mem } => { - let dst = format_reg(*dst.to_reg()); + let dst = RegNameDisplay(*dst.to_reg()); let mem = mem.to_string(); format!("{dst} = load_addr {mem}") } @@ -770,7 +775,7 @@ impl Inst { ty, flags, } => { - let dst = format_reg(*dst.to_reg()); + let dst = RegNameDisplay(*dst.to_reg()); let ty = ty.bits(); let mem = mem.to_string(); format!("{dst} = xload{ty} {mem} // flags ={flags}") @@ -784,7 +789,7 @@ impl Inst { } => { let ty = ty.bits(); let mem = mem.to_string(); - let src = format_reg(**src); + let src = RegNameDisplay(**src); format!("xstore{ty} {mem}, {src} // flags = {flags}") } @@ -794,7 +799,7 @@ impl Inst { ty, flags, } => { - let dst = format_reg(*dst.to_reg()); + let dst = RegNameDisplay(*dst.to_reg()); let ty = ty.bits(); let mem = mem.to_string(); format!("{dst} = fload{ty} {mem} // flags ={flags}") @@ -808,7 +813,7 @@ impl Inst { } => { let ty = ty.bits(); let mem = mem.to_string(); - let src = format_reg(**src); + let src = RegNameDisplay(**src); format!("fstore{ty} {mem}, {src} // flags = {flags}") } @@ -818,7 +823,7 @@ impl Inst { ty, flags, } => { - let dst = format_reg(*dst.to_reg()); + let dst = RegNameDisplay(*dst.to_reg()); let ty = ty.bits(); let mem = mem.to_string(); format!("{dst} = vload{ty} {mem} // flags ={flags}") @@ -832,7 +837,7 @@ impl Inst { } => { let ty = ty.bits(); let mem = mem.to_string(); - let src = format_reg(**src); + let src = RegNameDisplay(**src); format!("vstore{ty} {mem}, {src} // flags = {flags}") } @@ -841,15 +846,15 @@ impl Inst { default, targets, } => { - let idx = format_reg(**idx); + let idx = RegNameDisplay(**idx); format!("br_table {idx} {default:?} {targets:?}") } - Inst::Raw { raw } => generated::print(raw), + Inst::Raw { raw } => format!("{}", generated::RawInstDisplay(raw)), Inst::EmitIsland { space_needed } => format!("emit_island {space_needed}"), Inst::LabelAddress { dst, label } => { - let dst = format_reg(dst.to_reg().to_reg()); + let dst = RegNameDisplay(dst.to_reg().to_reg()); format!("label_address {dst}, {label:?}") }