Skip to content

Commit 66a1a6f

Browse files
committed
ZJIT: Add HIR Comment insn
Useful for adding comments to HIR/LIR/disasm that are not specific to an instruction. Possibly most useful for temporarily printing more information while debugging by keeping the statements interleaved with the HIR. With a local change like this diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index bff384f..de5b41caa1 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -2491,6 +2491,8 @@ fn type_specialize(&mut self) { cme = unsafe { rb_aliased_callable_method_entry(cme) }; def_type = unsafe { get_cme_def_type(cme) }; } + eprintln!("WTH"); + hir_comment!(self, block, "HOWDY def_type {:?}", def_type); if def_type == VM_METHOD_TYPE_ISEQ { // TODO(max): Allow non-iseq; cache cme // Only specialize positional-positional calls The print statement (1) shows up early (anywhere) whereas the HIR comment (2) is interleaved with the rest of the HIR so you can easily correlate debug info to the compilation of whatever function you are observing: 1. WTH Optimized HIR: fn test@test.rb:2: bb0(): EntryPoint interpreter v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:Fixnum[1] = Const Value(1) 2. # HOWDY def_type 0 PatchPoint MethodRedefined(Object@0x10184ed10, foo@0x9c01, cme:0x101967060) The comments show up in HIR, LIR, and disasm: bb2(v6:BasicObject): v11:Fixnum[1] = Const Value(1) # HOWDY def_type 0 PatchPoint MethodRedefined(Object@0x1220fed10, foo@0x9c01, cme:0x123717060) -- PatchPoint Exit(PatchPoint(NoTracePoint)) # Insn: v11 Const Value(1) # Insn: v18 # HOWDY def_type 0 # Insn: v19 PatchPoint MethodRedefined(Object@0x103aaed00, foo@0x9c01, cme:0x103bc7080) PatchPoint Exit(PatchPoint(MethodRedefined(Object@0x103aaed00, foo@0x9c01, cme:0x103bc7080))) -- 0x1230bc0f0: nop # Insn: v11 Const Value(1) # Insn: v18 # HOWDY def_type 0 # Insn: v19 PatchPoint MethodRedefined(Object@0x103c6ed20, foo@0x9c01, cme:0x103d87070) 0x1230bc0f4: nop
1 parent f261909 commit 66a1a6f

3 files changed

Lines changed: 60 additions & 2 deletions

File tree

zjit/src/codegen.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
594594
}
595595

596596
let out_opnd = match insn {
597+
Insn::Comment { .. } => return Ok(()), // comment instruction, no code generation
597598
&Insn::Const { val: Const::Value(val) } => gen_const_value(val),
598599
&Insn::Const { val: Const::CPtr(val) } => gen_const_cptr(val),
599600
&Insn::Const { val: Const::CInt64(val) } => gen_const_long(val),

zjit/src/hir.rs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,26 @@ use SendFallbackReason::*;
2424
pub(crate) mod tests;
2525
mod opt_tests;
2626

27+
#[allow(unused_macros)]
28+
macro_rules! hir_comment {
29+
($func:expr, $block:expr, $($arg:tt)*) => {
30+
// If a diagnostic dump is requested, enrich it with HIR comments. Otherwise, avoid
31+
// allocating comment strings or adding comment instructions that nobody can observe.
32+
let enable_comment = $crate::options::get_option_ref!(dump_hir_init).is_some() ||
33+
$crate::options::get_option_ref!(dump_hir_opt).is_some() ||
34+
$crate::options::get_option_ref!(dump_hir_graphviz).is_some() ||
35+
$crate::options::get_option!(dump_hir_iongraph) ||
36+
$crate::options::get_option_ref!(dump_lir).is_some() ||
37+
$crate::options::get_option_ref!(dump_disasm).is_some();
38+
if enable_comment {
39+
$func.push_comment($block, format!($($arg)*));
40+
}
41+
};
42+
}
43+
44+
#[allow(unused_imports)]
45+
pub(crate) use hir_comment;
46+
2747
/// An index of an [`Insn`] in a [`Function`]. This is a popular
2848
/// type since this effectively acts as a pointer to an [`Insn`].
2949
/// See also: [`Function::find`].
@@ -829,6 +849,9 @@ impl From<ID> for FieldName {
829849
/// helps with editing.
830850
#[derive(Debug, Clone)]
831851
pub enum Insn {
852+
/// Comment that can be inserted into HIR for diagnostics.
853+
Comment { message: String },
854+
832855
Const { val: Const },
833856
/// SSA block parameter. Also used for function parameters in the function's entry block.
834857
Param,
@@ -1192,7 +1215,8 @@ pub enum Insn {
11921215
macro_rules! for_each_operand_impl {
11931216
($self:expr, $visit_one:ident, $visit_many:ident) => {
11941217
match $self {
1195-
Insn::Const { .. }
1218+
Insn::Comment { .. }
1219+
| Insn::Const { .. }
11961220
| Insn::Param
11971221
| Insn::LoadArg { .. }
11981222
| Insn::Entries { .. }
@@ -1501,7 +1525,8 @@ impl Insn {
15011525
/// Not every instruction returns a value. Return true if the instruction does and false otherwise.
15021526
pub fn has_output(&self) -> bool {
15031527
match self {
1504-
Insn::Jump(_)
1528+
Insn::Comment { .. }
1529+
| Insn::Jump(_)
15051530
| Insn::Entries { .. }
15061531
| Insn::CondBranch { .. } | Insn::EntryPoint { .. } | Insn::Return { .. }
15071532
| Insn::PatchPoint { .. } | Insn::SetIvar { .. } | Insn::SetClassVar { .. } | Insn::ArrayExtend { .. }
@@ -1561,6 +1586,7 @@ impl Insn {
15611586
fn effects_of(&self) -> Effect {
15621587
const allocates: Effect = Effect::read_write(abstract_heaps::PC.union(abstract_heaps::Allocator), abstract_heaps::Allocator);
15631588
match &self {
1589+
Insn::Comment { .. } => effects::Empty,
15641590
Insn::Const { .. } => effects::Empty,
15651591
Insn::Param { .. } => effects::Empty,
15661592
Insn::LoadArg { .. } => effects::Empty,
@@ -1745,6 +1771,12 @@ impl Insn {
17451771
/// Note: These are restrictions on the `write` `EffectSet` only. Even instructions with
17461772
/// `read: effects::Any` could potentially be omitted.
17471773
fn is_elidable(&self) -> bool {
1774+
// Comments intentionally have no semantic effect, but they are diagnostics that should
1775+
// survive DCE so optimized HIR dumps retain the information callers inserted.
1776+
if matches!(self, Insn::Comment { .. }) {
1777+
return false;
1778+
}
1779+
17481780
abstract_heaps::Allocator.includes(self.effects_of().write_bits())
17491781
}
17501782
}
@@ -1813,6 +1845,7 @@ static REGEXP_FLAGS: &[(u32, &str)] = &[
18131845
impl<'a> std::fmt::Display for InsnPrinter<'a> {
18141846
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
18151847
match &self.inner {
1848+
Insn::Comment { message } => write!(f, "# {message}"),
18161849
Insn::Const { val } => { write!(f, "Const {}", val.print(self.ptr_map)) }
18171850
Insn::Param => { write!(f, "Param") }
18181851
Insn::LoadArg { idx, id, .. } => { write!(f, "LoadArg :{id}@{idx}") }
@@ -2695,6 +2728,10 @@ impl Function {
26952728
id
26962729
}
26972730

2731+
pub fn push_comment(&mut self, block: BlockId, message: String) -> InsnId {
2732+
self.push_insn(block, Insn::Comment { message })
2733+
}
2734+
26982735
// Add an instruction to an SSA block
26992736
fn push_insn_id(&mut self, block: BlockId, insn_id: InsnId) -> InsnId {
27002737
self.blocks[block.0].insns.push(insn_id);
@@ -2887,6 +2924,7 @@ impl Function {
28872924
Insn::Param => unimplemented!("params should not be present in block.insns"),
28882925
Insn::LoadArg { val_type, .. } => *val_type,
28892926
Insn::SetGlobal { .. } | Insn::Jump(_) | Insn::Entries { .. } | Insn::EntryPoint { .. }
2927+
| Insn::Comment { .. }
28902928
| Insn::CondBranch { .. } | Insn::Return { .. } | Insn::Throw { .. }
28912929
| Insn::PatchPoint { .. } | Insn::SetIvar { .. } | Insn::SetClassVar { .. } | Insn::ArrayExtend { .. }
28922930
| Insn::ArrayPush { .. } | Insn::SideExit { .. } | Insn::SetLocal { .. }
@@ -5952,6 +5990,7 @@ impl Function {
59525990
match insn {
59535991
// Instructions with no InsnId operands (except state) or nothing to assert
59545992
Insn::Const { .. }
5993+
| Insn::Comment { .. }
59555994
| Insn::Param
59565995
| Insn::LoadArg { .. }
59575996
| Insn::PutSpecialObject { .. }

zjit/src/hir/opt_tests.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2413,6 +2413,24 @@ mod hir_opt_tests {
24132413
");
24142414
}
24152415

2416+
#[test]
2417+
fn test_do_not_eliminate_comment() {
2418+
let mut function = Function::new(std::ptr::null());
2419+
let block = function.entry_block;
2420+
2421+
let comment = function.push_comment(block, "diagnostic".to_string());
2422+
let dead_const = function.push_insn(block, Insn::Const { val: Const::CBool(false) });
2423+
let return_val = function.push_insn(block, Insn::Const { val: Const::CBool(true) });
2424+
function.push_insn(block, Insn::Return { val: return_val });
2425+
function.seal_entries();
2426+
2427+
function.eliminate_dead_code();
2428+
2429+
let insns = &function.blocks[block.0].insns;
2430+
assert!(insns.contains(&comment));
2431+
assert!(!insns.contains(&dead_const));
2432+
}
2433+
24162434
#[test]
24172435
fn test_eliminate_new_array() {
24182436
eval("

0 commit comments

Comments
 (0)