feat(joinir): Phase 195 - Unified JoinLoopTrace for all JoinIR debug output
Created centralized tracing module for JoinIR loop lowering operations,
consolidating scattered eprintln! calls into a single SSOT interface.
# Implementation
1. **Created trace.rs module** (~233 lines)
- JoinLoopTrace struct with env var controls
- Unified API: pattern(), varmap(), joinir_stats(), phi(), merge(), etc.
- Global singleton via trace() function
- Supports 5 env vars: NYASH_TRACE_VARMAP, NYASH_JOINIR_DEBUG,
NYASH_OPTION_C_DEBUG, NYASH_JOINIR_MAINLINE_DEBUG, NYASH_LOOPFORM_DEBUG
2. **Updated debug.rs** - Delegates trace_varmap() to JoinLoopTrace
3. **Updated routing.rs** - All eprintln! replaced with trace calls (10 instances)
4. **Updated pattern routers** - All 3 patterns now use unified trace
- pattern1_minimal.rs: 6 replacements
- pattern2_with_break.rs: 6 replacements
- pattern3_with_if_phi.rs: 6 replacements
- router.rs: 2 replacements
5. **Updated merge/block_allocator.rs** - 6 eprintln! → trace calls
# Benefits
- **Single Source of Truth**: All trace control through environment variables
- **Consistent Format**: Unified [trace:*] prefix for easy filtering
- **Zero Overhead**: No output when env vars unset
- **Easy Extension**: Add new trace points via existing API
- **Better Debug Experience**: Structured output with clear categories
# Testing
✅ cargo build --release - Success
✅ NYASH_TRACE_VARMAP=1 - Shows varmap traces only
✅ NYASH_JOINIR_DEBUG=1 - Shows joinir + blocks + routing traces
✅ No env vars - No debug output
✅ apps/tests/loop_min_while.hako - All tests pass
# Related
- Phase 191-194 groundwork (modular merge structure)
- NYASH_TRACE_VARMAP added today for variable_map debugging
- Consolidates ~80 scattered eprintln! calls across JoinIR
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -3,6 +3,7 @@
|
||||
use crate::ast::ASTNode;
|
||||
use crate::mir::builder::MirBuilder;
|
||||
use crate::mir::ValueId;
|
||||
use super::super::trace;
|
||||
|
||||
/// Phase 194: Detection function for Pattern 1
|
||||
///
|
||||
@ -55,9 +56,8 @@ impl MirBuilder {
|
||||
use crate::mir::BasicBlockId;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
if debug {
|
||||
eprintln!("[cf_loop/joinir/pattern1] Calling Pattern 1 minimal lowerer");
|
||||
}
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().debug("pattern1", "Calling Pattern 1 minimal lowerer");
|
||||
|
||||
// Phase 188-Impl-2: Extract loop variable from condition
|
||||
// For `i < 3`, extract `i` and look up its ValueId in variable_map
|
||||
@ -73,12 +73,8 @@ impl MirBuilder {
|
||||
)
|
||||
})?;
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir/pattern1] Loop variable '{}' → {:?}",
|
||||
loop_var_name, loop_var_id
|
||||
);
|
||||
}
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().varmap("pattern1_start", &self.variable_map);
|
||||
|
||||
// Create a minimal LoopScopeShape (Phase 188: hardcoded for loop_min_while.hako)
|
||||
// Pattern 1 lowerer ignores the scope anyway, so this is just a placeholder
|
||||
@ -108,19 +104,22 @@ impl MirBuilder {
|
||||
let join_module = match lower_simple_while_minimal(scope, Some(ctx)) {
|
||||
Some(module) => module,
|
||||
None => {
|
||||
if debug {
|
||||
eprintln!("[cf_loop/joinir/pattern1] Pattern 1 lowerer returned None");
|
||||
}
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().debug("pattern1", "Pattern 1 lowerer returned None");
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir/pattern1] JoinModule generated with {} functions",
|
||||
join_module.functions.len()
|
||||
);
|
||||
}
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().joinir_stats(
|
||||
"pattern1",
|
||||
join_module.functions.len(),
|
||||
join_module
|
||||
.functions
|
||||
.values()
|
||||
.map(|f| f.body.len())
|
||||
.sum(),
|
||||
);
|
||||
|
||||
// Convert JoinModule to MirModule
|
||||
// Phase 188: Pass empty meta map since Pattern 1 lowerer doesn't use metadata
|
||||
@ -130,12 +129,16 @@ impl MirBuilder {
|
||||
let mir_module = convert_join_module_to_mir_with_meta(&join_module, &empty_meta)
|
||||
.map_err(|e| format!("[cf_loop/joinir/pattern1] MIR conversion failed: {:?}", e))?;
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir/pattern1] MirModule generated with {} functions",
|
||||
mir_module.functions.len()
|
||||
);
|
||||
}
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().joinir_stats(
|
||||
"pattern1",
|
||||
mir_module.functions.len(),
|
||||
mir_module
|
||||
.functions
|
||||
.values()
|
||||
.map(|f| f.blocks.len())
|
||||
.sum(),
|
||||
);
|
||||
|
||||
// Merge JoinIR blocks into current function
|
||||
// Phase 188-Impl-3: Create and pass JoinInlineBoundary for Pattern 1
|
||||
@ -163,12 +166,8 @@ impl MirBuilder {
|
||||
|
||||
let void_val = crate::mir::builder::emission::constant::emit_void(self);
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir/pattern1] Loop complete, returning Void {:?}",
|
||||
void_val
|
||||
);
|
||||
}
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().debug("pattern1", &format!("Loop complete, returning Void {:?}", void_val));
|
||||
|
||||
Ok(Some(void_val))
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
use crate::ast::ASTNode;
|
||||
use crate::mir::builder::MirBuilder;
|
||||
use crate::mir::ValueId;
|
||||
use super::super::trace;
|
||||
|
||||
/// Phase 194: Detection function for Pattern 2
|
||||
///
|
||||
@ -46,9 +47,8 @@ impl MirBuilder {
|
||||
use crate::mir::BasicBlockId;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
if debug {
|
||||
eprintln!("[cf_loop/joinir/pattern2] Calling Pattern 2 minimal lowerer");
|
||||
}
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().debug("pattern2", "Calling Pattern 2 minimal lowerer");
|
||||
|
||||
// Phase 188-Impl-2: Extract loop variable from condition
|
||||
// For `i < 3`, extract `i` and look up its ValueId in variable_map
|
||||
@ -64,12 +64,8 @@ impl MirBuilder {
|
||||
)
|
||||
})?;
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir/pattern2] Loop variable '{}' → {:?}",
|
||||
loop_var_name, loop_var_id
|
||||
);
|
||||
}
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().varmap("pattern2_start", &self.variable_map);
|
||||
|
||||
// Create a minimal LoopScopeShape (Phase 188: hardcoded for joinir_min_loop.hako)
|
||||
// Pattern 2 lowerer ignores the scope anyway, so this is just a placeholder
|
||||
@ -91,19 +87,18 @@ impl MirBuilder {
|
||||
let join_module = match lower_loop_with_break_minimal(scope) {
|
||||
Some(module) => module,
|
||||
None => {
|
||||
if debug {
|
||||
eprintln!("[cf_loop/joinir/pattern2] Pattern 2 lowerer returned None");
|
||||
}
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().debug("pattern2", "Pattern 2 lowerer returned None");
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir/pattern2] JoinModule generated with {} functions",
|
||||
join_module.functions.len()
|
||||
);
|
||||
}
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().joinir_stats(
|
||||
"pattern2",
|
||||
join_module.functions.len(),
|
||||
join_module.functions.values().map(|f| f.body.len()).sum(),
|
||||
);
|
||||
|
||||
// Convert JoinModule to MirModule
|
||||
// Phase 188: Pass empty meta map since Pattern 2 lowerer doesn't use metadata
|
||||
@ -113,12 +108,12 @@ impl MirBuilder {
|
||||
let mir_module = convert_join_module_to_mir_with_meta(&join_module, &empty_meta)
|
||||
.map_err(|e| format!("[cf_loop/joinir/pattern2] MIR conversion failed: {:?}", e))?;
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir/pattern2] MirModule generated with {} functions",
|
||||
mir_module.functions.len()
|
||||
);
|
||||
}
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().joinir_stats(
|
||||
"pattern2",
|
||||
mir_module.functions.len(),
|
||||
mir_module.functions.values().map(|f| f.blocks.len()).sum(),
|
||||
);
|
||||
|
||||
// Merge JoinIR blocks into current function
|
||||
// Phase 188-Impl-2: Create and pass JoinInlineBoundary for Pattern 2
|
||||
@ -133,12 +128,8 @@ impl MirBuilder {
|
||||
// The subsequent "return i" statement will emit its own Load + Return
|
||||
let void_val = crate::mir::builder::emission::constant::emit_void(self);
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir/pattern2] Loop complete, returning Void {:?}",
|
||||
void_val
|
||||
);
|
||||
}
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().debug("pattern2", &format!("Loop complete, returning Void {:?}", void_val));
|
||||
|
||||
Ok(Some(void_val))
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
use crate::ast::ASTNode;
|
||||
use crate::mir::builder::MirBuilder;
|
||||
use crate::mir::ValueId;
|
||||
use super::super::trace;
|
||||
|
||||
/// Phase 194: Detection function for Pattern 3
|
||||
///
|
||||
@ -50,9 +51,8 @@ impl MirBuilder {
|
||||
use crate::mir::BasicBlockId;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
if debug {
|
||||
eprintln!("[cf_loop/joinir/pattern3] Calling Pattern 3 minimal lowerer");
|
||||
}
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().debug("pattern3", "Calling Pattern 3 minimal lowerer");
|
||||
|
||||
// Phase 188-Impl-3: Extract loop variable from condition
|
||||
// For `i <= 5`, extract `i` and look up its ValueId in variable_map
|
||||
@ -80,12 +80,8 @@ impl MirBuilder {
|
||||
)
|
||||
})?;
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir/pattern3] Loop variables: '{}' → {:?}, 'sum' → {:?}",
|
||||
loop_var_name, loop_var_id, sum_var_id
|
||||
);
|
||||
}
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().varmap("pattern3_start", &self.variable_map);
|
||||
|
||||
// Create a minimal LoopScopeShape (Phase 188: hardcoded for loop_if_phi.hako)
|
||||
// Pattern 3 lowerer ignores the scope anyway, so this is just a placeholder
|
||||
@ -107,19 +103,18 @@ impl MirBuilder {
|
||||
let join_module = match lower_loop_with_if_phi_pattern(scope) {
|
||||
Some(module) => module,
|
||||
None => {
|
||||
if debug {
|
||||
eprintln!("[cf_loop/joinir/pattern3] Pattern 3 lowerer returned None");
|
||||
}
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().debug("pattern3", "Pattern 3 lowerer returned None");
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir/pattern3] JoinModule generated with {} functions",
|
||||
join_module.functions.len()
|
||||
);
|
||||
}
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().joinir_stats(
|
||||
"pattern3",
|
||||
join_module.functions.len(),
|
||||
join_module.functions.values().map(|f| f.body.len()).sum(),
|
||||
);
|
||||
|
||||
// Convert JoinModule to MirModule
|
||||
// Phase 188: Pass empty meta map since Pattern 3 lowerer doesn't use metadata
|
||||
@ -129,12 +124,12 @@ impl MirBuilder {
|
||||
let mir_module = convert_join_module_to_mir_with_meta(&join_module, &empty_meta)
|
||||
.map_err(|e| format!("[cf_loop/joinir/pattern3] MIR conversion failed: {:?}", e))?;
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir/pattern3] MirModule generated with {} functions",
|
||||
mir_module.functions.len()
|
||||
);
|
||||
}
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().joinir_stats(
|
||||
"pattern3",
|
||||
mir_module.functions.len(),
|
||||
mir_module.functions.values().map(|f| f.blocks.len()).sum(),
|
||||
);
|
||||
|
||||
// Merge JoinIR blocks into current function
|
||||
// Phase 190: Use explicit LoopExitBinding for Pattern 3
|
||||
@ -159,12 +154,8 @@ impl MirBuilder {
|
||||
// この関数では Void を返すだけでよい(戻り値は後続の `return sum` が扱う)。
|
||||
let void_val = crate::mir::builder::emission::constant::emit_void(self);
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir/pattern3] Loop complete, returning Void {:?}",
|
||||
void_val
|
||||
);
|
||||
}
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().debug("pattern3", &format!("Loop complete, returning Void {:?}", void_val));
|
||||
|
||||
Ok(Some(void_val))
|
||||
}
|
||||
|
||||
@ -115,23 +115,23 @@ pub fn route_loop_pattern(
|
||||
builder: &mut MirBuilder,
|
||||
ctx: &LoopPatternContext,
|
||||
) -> Result<Option<ValueId>, String> {
|
||||
use super::super::trace;
|
||||
|
||||
// Patterns are already sorted by priority in the table
|
||||
// (Pattern 3 with priority 30 comes first, then Pattern 1 with priority 10, etc.)
|
||||
// This ensures Pattern 3 is checked before Pattern 1, avoiding incorrect routing.
|
||||
|
||||
for entry in LOOP_PATTERNS {
|
||||
if (entry.detect)(builder, ctx) {
|
||||
// Log which pattern matched (for debugging)
|
||||
if ctx.debug || std::env::var("NYASH_TRACE_VARMAP").is_ok() {
|
||||
eprintln!("[route] Pattern '{}' matched for function '{}'", entry.name, ctx.func_name);
|
||||
}
|
||||
// Phase 195: Use unified trace for pattern matching
|
||||
trace::trace().pattern("route", entry.name, true);
|
||||
return (entry.lower)(builder, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
// No pattern matched - fall through to legacy path
|
||||
if ctx.debug {
|
||||
eprintln!("[route] No pattern matched for function '{}', falling back to legacy", ctx.func_name);
|
||||
trace::trace().debug("route", &format!("No pattern matched for function '{}', falling back to legacy", ctx.func_name));
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user