refactor(joinir): Phase 82-83 - Debug flag SSOT + Fallback verification
Phase 82: Centralized JoinIR debug flag reading - Added is_joinir_debug() SSOT function in joinir_flags.rs - Replaced 16 direct env::var() calls across 8 files - Updated docs to recommend HAKO_JOINIR_DEBUG (NYASH_ deprecated) - Backward compat: Both env vars work Phase 83: Verified promoted carrier fallback behavior - Confirmed NO fallback to name-based lookup for DigitPos/Trim - Documented fallback expectations in Phase 80/81 docs - Added verification commands and expected output Changes: - src/config/env/joinir_flags.rs: +187 lines (new SSOT module) - 8 files: env var reads → is_joinir_debug() calls - 3 docs: HAKO_JOINIR_DEBUG examples + fallback sections - 1 summary doc: phase82-83-debug-flag-ssot-summary.md Tests: 970/970 lib PASS, 58/58 normalized_dev PASS Impact: Dev-only (zero production changes)
This commit is contained in:
186
src/config/env/joinir_flags.rs
vendored
Normal file
186
src/config/env/joinir_flags.rs
vendored
Normal file
@ -0,0 +1,186 @@
|
||||
//! JoinIR-related environment flags
|
||||
//!
|
||||
//! This module groups all JoinIR feature flags and environment variable controls.
|
||||
//! Use this for IDE autocomplete to discover JoinIR flags easily.
|
||||
|
||||
use super::{env_bool, env_flag, warn_alias_once};
|
||||
|
||||
// ---- Phase 29/30 JoinIR toggles ----
|
||||
/// JoinIR experiment mode. Required for JoinIR-related experimental paths.
|
||||
/// Set NYASH_JOINIR_EXPERIMENT=1 to enable.
|
||||
pub fn joinir_experiment_enabled() -> bool {
|
||||
env_bool("NYASH_JOINIR_EXPERIMENT")
|
||||
}
|
||||
|
||||
/// JoinIR core policy: **always ON** after LoopBuilder removal.
|
||||
/// - `NYASH_JOINIR_CORE` is deprecated(0 を指定しても警告して無視する)
|
||||
/// - JoinIR を OFF にするモードは提供しない(Fail-Fast 原則、フォールバックなし)
|
||||
pub fn joinir_core_enabled() -> bool {
|
||||
if let Some(v) = env_flag("NYASH_JOINIR_CORE") {
|
||||
if !v {
|
||||
warn_joinir_core_off_ignored();
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn warn_joinir_core_off_ignored() {
|
||||
use std::sync::Once;
|
||||
static WARNED_JOINIR_CORE_OFF: Once = Once::new();
|
||||
WARNED_JOINIR_CORE_OFF.call_once(|| {
|
||||
eprintln!(
|
||||
"[deprecate/env] NYASH_JOINIR_CORE=0 is ignored; JoinIR core is always on (LoopBuilder is removed)"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// JoinIR VM bridge mode. When enabled with NYASH_JOINIR_EXPERIMENT=1,
|
||||
/// specific functions can be executed via JoinIR → VM bridge instead of direct MIR → VM.
|
||||
/// Set NYASH_JOINIR_VM_BRIDGE=1 to enable.
|
||||
pub fn joinir_vm_bridge_enabled() -> bool {
|
||||
joinir_core_enabled() && env_bool("NYASH_JOINIR_VM_BRIDGE")
|
||||
}
|
||||
|
||||
/// JoinIR strict mode: when enabled, JoinIR 対象のフォールバックを禁止する。
|
||||
/// 既定OFF。NYASH_JOINIR_STRICT=1 のときのみ有効。
|
||||
pub fn joinir_strict_enabled() -> bool {
|
||||
env_flag("NYASH_JOINIR_STRICT").unwrap_or(false)
|
||||
}
|
||||
|
||||
/// JoinIR VM bridge debug output. Enables verbose logging of JoinIR→MIR conversion.
|
||||
/// Set NYASH_JOINIR_VM_BRIDGE_DEBUG=1 to enable.
|
||||
pub fn joinir_vm_bridge_debug() -> bool {
|
||||
env_bool("NYASH_JOINIR_VM_BRIDGE_DEBUG")
|
||||
}
|
||||
|
||||
/// JoinIR LLVM experiment mode. When enabled with NYASH_JOINIR_EXPERIMENT=1,
|
||||
/// enables experimental JoinIR→MIR'→LLVM path for specific functions (e.g., Main.skip/1).
|
||||
/// This is a dev-only toggle for testing PHI normalization via JoinIR in the LLVM path.
|
||||
/// Set NYASH_JOINIR_LLVM_EXPERIMENT=1 to enable.
|
||||
pub fn joinir_llvm_experiment_enabled() -> bool {
|
||||
joinir_core_enabled() && env_bool("NYASH_JOINIR_LLVM_EXPERIMENT")
|
||||
}
|
||||
|
||||
/// Phase 33: JoinIR If Select 実験の有効化
|
||||
/// Primary: HAKO_JOINIR_IF_SELECT (Phase 33-8+).
|
||||
pub fn joinir_if_select_enabled() -> bool {
|
||||
// Core ON なら既定で有効化(JoinIR 本線化を優先)
|
||||
if joinir_core_enabled() {
|
||||
return true;
|
||||
}
|
||||
// Primary: HAKO_JOINIR_IF_SELECT
|
||||
if let Some(v) = env_flag("HAKO_JOINIR_IF_SELECT") {
|
||||
return v;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Phase 33-8: JoinIR Stage-1 rollout toggle
|
||||
/// Set HAKO_JOINIR_STAGE1=1 to enable JoinIR lowering for Stage-1 functions.
|
||||
pub fn joinir_stage1_enabled() -> bool {
|
||||
// Primary: HAKO_JOINIR_STAGE1
|
||||
if let Some(v) = env_flag("HAKO_JOINIR_STAGE1") {
|
||||
return v;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Phase 33-8: JoinIR debug log level (0-3)
|
||||
/// - 0: No logs (default)
|
||||
/// - 1: Basic logs (which functions were lowered)
|
||||
/// - 2: Pattern matching details (CFG analysis)
|
||||
/// - 3: Full dump (all variables, all instructions)
|
||||
pub fn joinir_debug_level() -> u8 {
|
||||
// Primary: HAKO_JOINIR_DEBUG
|
||||
if let Ok(v) = std::env::var("HAKO_JOINIR_DEBUG") {
|
||||
return v.parse().unwrap_or(0);
|
||||
}
|
||||
// Fallback: NYASH_JOINIR_DEBUG (deprecated)
|
||||
if let Ok(v) = std::env::var("NYASH_JOINIR_DEBUG") {
|
||||
warn_alias_once("NYASH_JOINIR_DEBUG", "HAKO_JOINIR_DEBUG");
|
||||
return v.parse().unwrap_or(0);
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
/// Dev-only convenience switch to bundle experimental JoinIR knobs.
|
||||
/// - NYASH_JOINIR_DEV=1 enables
|
||||
/// - Otherwise inherits from joinir_debug_level()>0 (opt-in debug)
|
||||
pub fn joinir_dev_enabled() -> bool {
|
||||
env_bool("NYASH_JOINIR_DEV") || joinir_debug_level() > 0
|
||||
}
|
||||
|
||||
/// Phase 61-2: If-in-loop JoinIR dry-run有効化
|
||||
///
|
||||
/// `HAKO_JOINIR_IF_IN_LOOP_DRYRUN=1` でdry-runモードを有効化
|
||||
///
|
||||
/// dry-runモード:
|
||||
/// - JoinIR経路でPHI仕様を計算
|
||||
/// - PhiBuilderBox経路と比較
|
||||
/// - 実際のPHI生成はPhiBuilderBoxを使用(安全)
|
||||
pub fn joinir_if_in_loop_dryrun_enabled() -> bool {
|
||||
env_bool("HAKO_JOINIR_IF_IN_LOOP_DRYRUN")
|
||||
}
|
||||
|
||||
/// Phase 61-3: If-in-loop JoinIR本番経路有効化
|
||||
///
|
||||
/// `HAKO_JOINIR_IF_IN_LOOP_ENABLE=1` でJoinIR本番経路を有効化
|
||||
///
|
||||
/// 動作:
|
||||
/// - ON: JoinIR + IfInLoopPhiEmitter経路(PhiBuilderBox不使用)
|
||||
/// - OFF: PhiBuilderBox経路(既存フォールバック)
|
||||
///
|
||||
/// 前提条件:
|
||||
/// - JoinIR IfSelect 基盤(Phase 33)の有効化
|
||||
/// - dry-runモードとは独立(HAKO_JOINIR_IF_IN_LOOP_DRYRUN)
|
||||
///
|
||||
/// デフォルト: OFF(安全第一)
|
||||
pub fn joinir_if_in_loop_enable() -> bool {
|
||||
env_bool("HAKO_JOINIR_IF_IN_LOOP_ENABLE")
|
||||
}
|
||||
|
||||
/// Phase 61-4: ループ外If JoinIR経路有効化
|
||||
///
|
||||
/// `HAKO_JOINIR_IF_TOPLEVEL=1` でループ外IfのJoinIR経路を有効化
|
||||
///
|
||||
/// 動作:
|
||||
/// - ON: try_lower_if_to_joinir経路(if_form.rsで使用)
|
||||
/// - OFF: PhiBuilderBox経路(既存)
|
||||
///
|
||||
/// 前提条件:
|
||||
/// - HAKO_JOINIR_IF_SELECT=1(Phase 33基盤)
|
||||
///
|
||||
/// デフォルト: OFF(安全第一)
|
||||
pub fn joinir_if_toplevel_enabled() -> bool {
|
||||
env_bool("HAKO_JOINIR_IF_TOPLEVEL")
|
||||
}
|
||||
|
||||
/// Phase 61-4: ループ外If JoinIR dry-run有効化
|
||||
///
|
||||
/// `HAKO_JOINIR_IF_TOPLEVEL_DRYRUN=1` でdry-runモードを有効化
|
||||
///
|
||||
/// dry-runモード:
|
||||
/// - JoinIR経路を試行しログ出力
|
||||
/// - 実際のPHI生成は既存経路を使用(安全)
|
||||
pub fn joinir_if_toplevel_dryrun_enabled() -> bool {
|
||||
env_bool("HAKO_JOINIR_IF_TOPLEVEL_DRYRUN")
|
||||
}
|
||||
|
||||
/// LoopForm normalize flag (NYASH_LOOPFORM_NORMALIZE=1).
|
||||
pub fn loopform_normalize() -> bool {
|
||||
std::env::var("NYASH_LOOPFORM_NORMALIZE").ok().as_deref() == Some("1")
|
||||
}
|
||||
|
||||
/// JoinIR debug logging enabled check (SSOT).
|
||||
///
|
||||
/// Checks both HAKO_JOINIR_DEBUG and NYASH_JOINIR_DEBUG (legacy).
|
||||
/// Returns true if either env var is set to any value.
|
||||
///
|
||||
/// Recommended: Use HAKO_JOINIR_DEBUG=1
|
||||
/// Legacy: NYASH_JOINIR_DEBUG=1 (deprecated, but still works)
|
||||
///
|
||||
/// For fine-grained control, use `joinir_debug_level()` which returns 0-3.
|
||||
pub fn is_joinir_debug() -> bool {
|
||||
std::env::var("HAKO_JOINIR_DEBUG").is_ok()
|
||||
|| std::env::var("NYASH_JOINIR_DEBUG").is_ok()
|
||||
}
|
||||
@ -64,9 +64,10 @@ pub struct JoinLoopTrace {
|
||||
impl JoinLoopTrace {
|
||||
/// Create a new tracer, reading environment variables.
|
||||
pub fn new() -> Self {
|
||||
use crate::config::env::is_joinir_debug;
|
||||
Self {
|
||||
varmap_enabled: std::env::var("NYASH_TRACE_VARMAP").is_ok(),
|
||||
joinir_enabled: std::env::var("NYASH_JOINIR_DEBUG").is_ok(),
|
||||
joinir_enabled: is_joinir_debug(),
|
||||
phi_enabled: std::env::var("NYASH_OPTION_C_DEBUG").is_ok(),
|
||||
mainline_enabled: std::env::var("NYASH_JOINIR_MAINLINE_DEBUG").is_ok(),
|
||||
loopform_enabled: std::env::var("NYASH_LOOPFORM_DEBUG").is_ok(),
|
||||
|
||||
@ -138,9 +138,8 @@ impl CarrierBindingAssigner {
|
||||
};
|
||||
carrier.binding_id = Some(promoted_bid);
|
||||
|
||||
if std::env::var("NYASH_JOINIR_DEBUG").is_ok()
|
||||
|| std::env::var("JOINIR_TEST_DEBUG").is_ok()
|
||||
{
|
||||
use crate::config::env::is_joinir_debug;
|
||||
if is_joinir_debug() || std::env::var("JOINIR_TEST_DEBUG").is_ok() {
|
||||
eprintln!(
|
||||
"[phase78/carrier_assigner] '{}' (BindingId({})) → '{}' (BindingId({}))",
|
||||
original_name,
|
||||
|
||||
@ -650,7 +650,8 @@ impl CarrierInfo {
|
||||
/// we integrate BindingId tracking into the promotion pipeline.
|
||||
#[cfg(feature = "normalized_dev")]
|
||||
pub fn record_promoted_binding(&mut self, original_binding: BindingId, promoted_binding: BindingId) {
|
||||
if std::env::var("NYASH_JOINIR_DEBUG").is_ok() || std::env::var("JOINIR_TEST_DEBUG").is_ok() {
|
||||
use crate::config::env::is_joinir_debug;
|
||||
if is_joinir_debug() || std::env::var("JOINIR_TEST_DEBUG").is_ok() {
|
||||
eprintln!(
|
||||
"[binding_pilot/promoted_bindings] {} → {}",
|
||||
original_binding, promoted_binding
|
||||
|
||||
@ -307,10 +307,11 @@ impl ConditionEnv {
|
||||
binding_id: Option<BindingId>,
|
||||
name: &str,
|
||||
) -> Option<ValueId> {
|
||||
use crate::config::env::is_joinir_debug;
|
||||
if let Some(bid) = binding_id {
|
||||
// Try BindingId lookup first
|
||||
if let Some(&value_id) = self.binding_id_map.get(&bid) {
|
||||
if std::env::var("NYASH_JOINIR_DEBUG").is_ok() {
|
||||
if is_joinir_debug() {
|
||||
eprintln!(
|
||||
"[binding_pilot/hit] BindingId({}) -> ValueId({}) for '{}'",
|
||||
bid.0, value_id.0, name
|
||||
@ -320,7 +321,7 @@ impl ConditionEnv {
|
||||
} else {
|
||||
// BindingId miss, fall back to name
|
||||
let result = self.get(name);
|
||||
if std::env::var("NYASH_JOINIR_DEBUG").is_ok() {
|
||||
if is_joinir_debug() {
|
||||
eprintln!(
|
||||
"[binding_pilot/fallback] BindingId({}) miss, name '{}' -> {:?}",
|
||||
bid.0, name, result
|
||||
@ -331,7 +332,7 @@ impl ConditionEnv {
|
||||
} else {
|
||||
// Legacy: no BindingId, use name lookup
|
||||
let result = self.get(name);
|
||||
if std::env::var("NYASH_JOINIR_DEBUG").is_ok() {
|
||||
if is_joinir_debug() {
|
||||
eprintln!(
|
||||
"[binding_pilot/legacy] No BindingId, name '{}' -> {:?}",
|
||||
name, result
|
||||
|
||||
@ -266,10 +266,11 @@ impl<'a> ScopeManager for Pattern2ScopeManager<'a> {
|
||||
/// promoters populate promoted_bindings map and all call sites provide BindingId.
|
||||
#[cfg(feature = "normalized_dev")]
|
||||
fn lookup_with_binding(&self, binding_id: Option<BindingId>, name: &str) -> Option<ValueId> {
|
||||
use crate::config::env::is_joinir_debug;
|
||||
if let Some(bid) = binding_id {
|
||||
// Step 1: Try direct BindingId lookup in ConditionEnv (Phase 75)
|
||||
if let Some(value_id) = self.condition_env.resolve_var_with_binding(Some(bid), name) {
|
||||
if std::env::var("NYASH_JOINIR_DEBUG").is_ok() {
|
||||
if is_joinir_debug() {
|
||||
eprintln!(
|
||||
"[phase76/direct] BindingId({}) -> ValueId({}) for '{}'",
|
||||
bid.0, value_id.0, name
|
||||
@ -282,7 +283,7 @@ impl<'a> ScopeManager for Pattern2ScopeManager<'a> {
|
||||
if let Some(promoted_bid) = self.carrier_info.resolve_promoted_with_binding(bid) {
|
||||
// Promoted BindingId found, lookup in ConditionEnv
|
||||
if let Some(value_id) = self.condition_env.resolve_var_with_binding(Some(promoted_bid), name) {
|
||||
if std::env::var("NYASH_JOINIR_DEBUG").is_ok() {
|
||||
if is_joinir_debug() {
|
||||
eprintln!(
|
||||
"[phase76/promoted] BindingId({}) promoted to BindingId({}) -> ValueId({}) for '{}'",
|
||||
bid.0, promoted_bid.0, value_id.0, name
|
||||
@ -300,7 +301,7 @@ impl<'a> ScopeManager for Pattern2ScopeManager<'a> {
|
||||
bid.0, name
|
||||
);
|
||||
#[cfg(not(feature = "normalized_dev"))]
|
||||
if std::env::var("NYASH_JOINIR_DEBUG").is_ok() {
|
||||
if is_joinir_debug() {
|
||||
eprintln!(
|
||||
"[phase76/fallback] BindingId({}) miss, falling back to name '{}' lookup",
|
||||
bid.0, name
|
||||
|
||||
@ -173,7 +173,8 @@ impl LoopBodyCarrierPromoter {
|
||||
};
|
||||
}
|
||||
|
||||
if std::env::var("NYASH_JOINIR_DEBUG").is_ok() || std::env::var("JOINIR_TEST_DEBUG").is_ok() {
|
||||
use crate::config::env::is_joinir_debug;
|
||||
if is_joinir_debug() || std::env::var("JOINIR_TEST_DEBUG").is_ok() {
|
||||
eprintln!(
|
||||
"[promoter/pattern5] Phase 171-C: Found {} LoopBodyLocal variables: {:?}",
|
||||
body_locals.len(),
|
||||
@ -196,7 +197,7 @@ impl LoopBodyCarrierPromoter {
|
||||
// Phase 79: Use TrimDetector for pure detection logic
|
||||
if let Some(detection) = TrimDetector::detect(break_cond, request.loop_body, var_name)
|
||||
{
|
||||
if std::env::var("NYASH_JOINIR_DEBUG").is_ok() || std::env::var("JOINIR_TEST_DEBUG").is_ok() {
|
||||
if is_joinir_debug() || std::env::var("JOINIR_TEST_DEBUG").is_ok() {
|
||||
eprintln!(
|
||||
"[promoter/pattern5] Trim pattern detected! var='{}', literals={:?}",
|
||||
detection.match_var, detection.comparison_literals
|
||||
@ -231,7 +232,8 @@ impl LoopBodyCarrierPromoter {
|
||||
/// Phase 78: Log promotion errors with clear messages (for Trim pattern, gated)
|
||||
#[cfg(feature = "normalized_dev")]
|
||||
fn log_trim_promotion_error(error: &BindingRecordError) {
|
||||
if std::env::var("NYASH_JOINIR_DEBUG").is_ok() || std::env::var("JOINIR_TEST_DEBUG").is_ok() {
|
||||
use crate::config::env::is_joinir_debug;
|
||||
if is_joinir_debug() || std::env::var("JOINIR_TEST_DEBUG").is_ok() {
|
||||
match error {
|
||||
BindingRecordError::OriginalNotFound(name) => {
|
||||
eprintln!(
|
||||
|
||||
@ -129,7 +129,8 @@ impl DigitPosPromoter {
|
||||
};
|
||||
}
|
||||
|
||||
if std::env::var("NYASH_JOINIR_DEBUG").is_ok() || std::env::var("JOINIR_TEST_DEBUG").is_ok() {
|
||||
use crate::config::env::is_joinir_debug;
|
||||
if is_joinir_debug() || std::env::var("JOINIR_TEST_DEBUG").is_ok() {
|
||||
eprintln!(
|
||||
"[digitpos_promoter] Phase 224: Found {} LoopBodyLocal variables: {:?}",
|
||||
body_locals.len(),
|
||||
@ -162,7 +163,7 @@ impl DigitPosPromoter {
|
||||
}
|
||||
|
||||
let detection = detection.unwrap();
|
||||
if std::env::var("NYASH_JOINIR_DEBUG").is_ok() || std::env::var("JOINIR_TEST_DEBUG").is_ok() {
|
||||
if is_joinir_debug() || std::env::var("JOINIR_TEST_DEBUG").is_ok() {
|
||||
eprintln!(
|
||||
"[digitpos_promoter] Pattern detected: {} → {} (bool) + {} (int)",
|
||||
detection.var_name, detection.bool_carrier_name, detection.int_carrier_name
|
||||
@ -222,7 +223,7 @@ impl DigitPosPromoter {
|
||||
log_promotion_error(&e);
|
||||
}
|
||||
|
||||
if std::env::var("NYASH_JOINIR_DEBUG").is_ok() || std::env::var("JOINIR_TEST_DEBUG").is_ok() {
|
||||
if is_joinir_debug() || std::env::var("JOINIR_TEST_DEBUG").is_ok() {
|
||||
eprintln!(
|
||||
"[digitpos_promoter] Phase 247-EX: A-4 DigitPos pattern promoted: {} → {} (bool) + {} (i64)",
|
||||
detection.var_name, detection.bool_carrier_name, detection.int_carrier_name
|
||||
@ -252,7 +253,8 @@ impl DigitPosPromoter {
|
||||
/// Phase 78: Log promotion errors with clear messages (gated)
|
||||
#[cfg(feature = "normalized_dev")]
|
||||
fn log_promotion_error(error: &BindingRecordError) {
|
||||
if std::env::var("NYASH_JOINIR_DEBUG").is_ok() || std::env::var("JOINIR_TEST_DEBUG").is_ok() {
|
||||
use crate::config::env::is_joinir_debug;
|
||||
if is_joinir_debug() || std::env::var("JOINIR_TEST_DEBUG").is_ok() {
|
||||
match error {
|
||||
BindingRecordError::OriginalNotFound(name) => {
|
||||
eprintln!(
|
||||
|
||||
Reference in New Issue
Block a user