feat(joinir): Phase 33-8 Stage-1 rollout infrastructure
Add environment variable controls and debug logging for JoinIR lowering rollout.
Changes:
- Add HAKO_JOINIR_STAGE1 env var for Stage-1 function rollout control
- Add HAKO_JOINIR_DEBUG (0-3) for granular debug logging
- Level 0: Silent (default)
- Level 1: Basic lowering info
- Level 2: Pattern matching details
- Level 3: Full variable/instruction dump
- Implement 3-tier whitelist system:
- Tier 1: Test functions (always enabled)
- Tier 2: Stage-1 rollout (env-controlled)
- Tier 3: Explicit approvals (validated in Phase 33-4)
- Add A/B test automation script (tools/joinir_ab_test.sh)
- Update if_merge.rs and if_select.rs with debug_level support
Environment variables (with NYASH_* fallback for compatibility):
- HAKO_JOINIR_IF_SELECT: Enable JoinIR lowering
- HAKO_JOINIR_STAGE1: Enable Stage-1 function rollout
- HAKO_JOINIR_DEBUG: Debug log level (0-3)
A/B test verification: PASSED on joinir_if_merge_{simple,multiple}.hako
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -218,9 +218,51 @@ pub fn joinir_llvm_experiment_enabled() -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Phase 33: JoinIR If Select 実験の有効化
|
/// Phase 33: JoinIR If Select 実験の有効化
|
||||||
/// Set NYASH_JOINIR_IF_SELECT=1 to enable experimental If/Else → Select lowering.
|
/// Primary: HAKO_JOINIR_IF_SELECT (Phase 33-8+). Fallback: NYASH_JOINIR_IF_SELECT (deprecated).
|
||||||
pub fn joinir_if_select_enabled() -> bool {
|
pub fn joinir_if_select_enabled() -> bool {
|
||||||
env_bool("NYASH_JOINIR_IF_SELECT")
|
// Primary: HAKO_JOINIR_IF_SELECT
|
||||||
|
if let Some(v) = env_flag("HAKO_JOINIR_IF_SELECT") {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
// Fallback: NYASH_JOINIR_IF_SELECT (deprecated)
|
||||||
|
if env_bool("NYASH_JOINIR_IF_SELECT") {
|
||||||
|
warn_alias_once("NYASH_JOINIR_IF_SELECT", "HAKO_JOINIR_IF_SELECT");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
// Fallback: NYASH_JOINIR_STAGE1 (deprecated)
|
||||||
|
if env_bool("NYASH_JOINIR_STAGE1") {
|
||||||
|
warn_alias_once("NYASH_JOINIR_STAGE1", "HAKO_JOINIR_STAGE1");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// VM legacy by-name call fallback was removed (Phase 2 complete).
|
// VM legacy by-name call fallback was removed (Phase 2 complete).
|
||||||
|
|||||||
@ -11,7 +11,7 @@ use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
pub struct IfMergeLowerer {
|
pub struct IfMergeLowerer {
|
||||||
debug: bool,
|
debug_level: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 検出された IfMerge パターン情報
|
/// 検出された IfMerge パターン情報
|
||||||
@ -30,8 +30,13 @@ struct IfBranch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl IfMergeLowerer {
|
impl IfMergeLowerer {
|
||||||
pub fn new(debug: bool) -> Self {
|
pub fn new(debug_level: u8) -> Self {
|
||||||
Self { debug }
|
Self { debug_level }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Phase 33-8: debug-level backward compat wrapper
|
||||||
|
pub fn with_debug(debug: bool) -> Self {
|
||||||
|
Self { debug_level: if debug { 1 } else { 0 } }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// if/else が IfMerge に lowering できるかチェック
|
/// if/else が IfMerge に lowering できるかチェック
|
||||||
@ -47,13 +52,25 @@ impl IfMergeLowerer {
|
|||||||
) -> Option<JoinInst> {
|
) -> Option<JoinInst> {
|
||||||
let pattern = self.find_if_merge_pattern(func, if_block_id)?;
|
let pattern = self.find_if_merge_pattern(func, if_block_id)?;
|
||||||
|
|
||||||
if self.debug {
|
// Phase 33-8: Level 1 - Basic lowering info
|
||||||
|
if self.debug_level >= 1 {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[IfMergeLowerer] lowering to IfMerge with {} merge pairs",
|
"[IfMergeLowerer] ✅ lowering to IfMerge with {} merge pairs",
|
||||||
pattern.merge_pairs.len()
|
pattern.merge_pairs.len()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Phase 33-8: Level 3 - Full merge details
|
||||||
|
if self.debug_level >= 3 {
|
||||||
|
eprintln!("[IfMergeLowerer] cond: {:?}", pattern.cond);
|
||||||
|
for (i, pair) in pattern.merge_pairs.iter().enumerate() {
|
||||||
|
eprintln!(
|
||||||
|
"[IfMergeLowerer] pair[{}]: dst={:?}, then={:?}, else={:?}",
|
||||||
|
i, pair.dst, pair.then_val, pair.else_val
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// IfMerge 命令を生成
|
// IfMerge 命令を生成
|
||||||
Some(JoinInst::IfMerge {
|
Some(JoinInst::IfMerge {
|
||||||
cond: pattern.cond,
|
cond: pattern.cond,
|
||||||
@ -99,9 +116,10 @@ impl IfMergeLowerer {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if !is_then_return || !is_else_return {
|
if !is_then_return || !is_else_return {
|
||||||
if self.debug {
|
// Phase 33-8: Level 2 - Pattern matching details
|
||||||
|
if self.debug_level >= 2 {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[IfMergeLowerer] not return pattern (then={}, else={})",
|
"[IfMergeLowerer] ❌ not return pattern (then={}, else={})",
|
||||||
is_then_return, is_else_return
|
is_then_return, is_else_return
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -112,7 +130,8 @@ impl IfMergeLowerer {
|
|||||||
let then_writes = self.extract_written_vars(&then_block.instructions);
|
let then_writes = self.extract_written_vars(&then_block.instructions);
|
||||||
let else_writes = self.extract_written_vars(&else_block.instructions);
|
let else_writes = self.extract_written_vars(&else_block.instructions);
|
||||||
|
|
||||||
if self.debug {
|
// Phase 33-8: Level 3 - Full variable dump
|
||||||
|
if self.debug_level >= 3 {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[IfMergeLowerer] then writes: {:?}, else writes: {:?}",
|
"[IfMergeLowerer] then writes: {:?}, else writes: {:?}",
|
||||||
then_writes, else_writes
|
then_writes, else_writes
|
||||||
@ -123,8 +142,9 @@ impl IfMergeLowerer {
|
|||||||
let common_writes: HashSet<_> = then_writes.intersection(&else_writes).copied().collect();
|
let common_writes: HashSet<_> = then_writes.intersection(&else_writes).copied().collect();
|
||||||
|
|
||||||
if common_writes.is_empty() {
|
if common_writes.is_empty() {
|
||||||
if self.debug {
|
// Phase 33-8: Level 2 - Pattern matching details
|
||||||
eprintln!("[IfMergeLowerer] no common writes found");
|
if self.debug_level >= 2 {
|
||||||
|
eprintln!("[IfMergeLowerer] ❌ no common writes found");
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -230,7 +250,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_if_merge_lowerer_creation() {
|
fn test_if_merge_lowerer_creation() {
|
||||||
let lowerer = IfMergeLowerer::new(false);
|
let lowerer = IfMergeLowerer::new(0);
|
||||||
assert!(!lowerer.debug);
|
assert_eq!(lowerer.debug_level, 0);
|
||||||
|
|
||||||
|
let lowerer_compat = IfMergeLowerer::with_debug(true);
|
||||||
|
assert_eq!(lowerer_compat.debug_level, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use crate::mir::join_ir::JoinInst;
|
|||||||
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
|
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
|
||||||
|
|
||||||
pub struct IfSelectLowerer {
|
pub struct IfSelectLowerer {
|
||||||
debug: bool,
|
debug_level: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If/Else パターンの分類
|
/// If/Else パターンの分類
|
||||||
@ -37,8 +37,13 @@ struct IfBranch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl IfSelectLowerer {
|
impl IfSelectLowerer {
|
||||||
pub fn new(debug: bool) -> Self {
|
pub fn new(debug_level: u8) -> Self {
|
||||||
Self { debug }
|
Self { debug_level }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Phase 33-8: debug-level backward compat wrapper
|
||||||
|
pub fn with_debug(debug: bool) -> Self {
|
||||||
|
Self { debug_level: if debug { 1 } else { 0 } }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// if/else が Select に lowering できるかチェック
|
/// if/else が Select に lowering できるかチェック
|
||||||
@ -54,13 +59,22 @@ impl IfSelectLowerer {
|
|||||||
) -> Option<JoinInst> {
|
) -> Option<JoinInst> {
|
||||||
let pattern = self.find_if_pattern(func, if_block_id)?;
|
let pattern = self.find_if_pattern(func, if_block_id)?;
|
||||||
|
|
||||||
if self.debug {
|
// Phase 33-8: Level 1 - Basic lowering info
|
||||||
|
if self.debug_level >= 1 {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[IfSelectLowerer] lowering {:?} pattern to Select",
|
"[IfSelectLowerer] ✅ lowering {:?} pattern to Select",
|
||||||
pattern.pattern_type
|
pattern.pattern_type
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Phase 33-8: Level 3 - Full pattern details
|
||||||
|
if self.debug_level >= 3 {
|
||||||
|
eprintln!("[IfSelectLowerer] cond: {:?}", pattern.cond);
|
||||||
|
eprintln!("[IfSelectLowerer] then_val: {:?}", pattern.then_val);
|
||||||
|
eprintln!("[IfSelectLowerer] else_val: {:?}", pattern.else_val);
|
||||||
|
eprintln!("[IfSelectLowerer] dst: {:?}", pattern.dst);
|
||||||
|
}
|
||||||
|
|
||||||
// Select 命令を生成
|
// Select 命令を生成
|
||||||
let dst = pattern.dst.unwrap_or(pattern.then_val);
|
let dst = pattern.dst.unwrap_or(pattern.then_val);
|
||||||
|
|
||||||
@ -99,8 +113,9 @@ impl IfSelectLowerer {
|
|||||||
|
|
||||||
// 3. simple パターンのチェック
|
// 3. simple パターンのチェック
|
||||||
if let Some(pattern) = self.try_match_simple_pattern(&branch, then_block, else_block) {
|
if let Some(pattern) = self.try_match_simple_pattern(&branch, then_block, else_block) {
|
||||||
if self.debug {
|
// Phase 33-8: Level 2 - Pattern matching details
|
||||||
eprintln!("[IfSelectLowerer] matched simple pattern");
|
if self.debug_level >= 2 {
|
||||||
|
eprintln!("[IfSelectLowerer] ✅ matched simple pattern");
|
||||||
}
|
}
|
||||||
return Some(pattern);
|
return Some(pattern);
|
||||||
}
|
}
|
||||||
@ -108,14 +123,16 @@ impl IfSelectLowerer {
|
|||||||
// 4. local パターンのチェック
|
// 4. local パターンのチェック
|
||||||
if let Some(pattern) = self.try_match_local_pattern(func, &branch, then_block, else_block)
|
if let Some(pattern) = self.try_match_local_pattern(func, &branch, then_block, else_block)
|
||||||
{
|
{
|
||||||
if self.debug {
|
// Phase 33-8: Level 2 - Pattern matching details
|
||||||
eprintln!("[IfSelectLowerer] matched local pattern");
|
if self.debug_level >= 2 {
|
||||||
|
eprintln!("[IfSelectLowerer] ✅ matched local pattern");
|
||||||
}
|
}
|
||||||
return Some(pattern);
|
return Some(pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.debug {
|
// Phase 33-8: Level 2 - Pattern matching details
|
||||||
eprintln!("[IfSelectLowerer] no pattern matched");
|
if self.debug_level >= 2 {
|
||||||
|
eprintln!("[IfSelectLowerer] ❌ no pattern matched");
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|||||||
@ -73,15 +73,29 @@ pub fn try_lower_if_to_joinir(
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Phase 33-7: 関数名ガード拡張(テスト + Stage-1/Stage-B 候補)
|
// Phase 33-8: デバッグログレベル取得(0-3)
|
||||||
let is_allowed = func.signature.name.starts_with("IfSelectTest.")
|
let debug_level = crate::config::env::joinir_debug_level();
|
||||||
|| func.signature.name.starts_with("IfMergeTest.") // Phase 33-7
|
let _debug = debug || debug_level >= 1;
|
||||||
|| func.signature.name.starts_with("Stage1JsonScannerTestBox.") // Phase 33-5 test
|
|
||||||
|| func.signature.name == "JsonShapeToMap._read_value_from_pair/1"
|
// 2. Phase 33-8: 関数名ガード拡張(テスト + Stage-1 rollout + 明示承認)
|
||||||
|| func.signature.name == "Stage1JsonScannerBox.value_start_after_key_pos/2";
|
let is_allowed =
|
||||||
|
// Test functions (always enabled)
|
||||||
|
func.signature.name.starts_with("IfSelectTest.") ||
|
||||||
|
func.signature.name.starts_with("IfMergeTest.") ||
|
||||||
|
func.signature.name.starts_with("Stage1JsonScannerTestBox.") || // Phase 33-5 test
|
||||||
|
|
||||||
|
// Stage-1 rollout (env-controlled)
|
||||||
|
(crate::config::env::joinir_stage1_enabled() &&
|
||||||
|
func.signature.name.starts_with("Stage1")) ||
|
||||||
|
|
||||||
|
// Explicit approvals (Phase 33-4で検証済み, always on)
|
||||||
|
matches!(func.signature.name.as_str(),
|
||||||
|
"JsonShapeToMap._read_value_from_pair/1" |
|
||||||
|
"Stage1JsonScannerBox.value_start_after_key_pos/2"
|
||||||
|
);
|
||||||
|
|
||||||
if !is_allowed {
|
if !is_allowed {
|
||||||
if debug {
|
if debug_level >= 2 {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[try_lower_if_to_joinir] skipping non-allowed function: {}",
|
"[try_lower_if_to_joinir] skipping non-allowed function: {}",
|
||||||
func.signature.name
|
func.signature.name
|
||||||
@ -90,15 +104,19 @@ pub fn try_lower_if_to_joinir(
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if debug_level >= 1 {
|
||||||
|
eprintln!("[try_lower_if_to_joinir] trying to lower {}", func.signature.name);
|
||||||
|
}
|
||||||
|
|
||||||
// 3. Phase 33-7: IfMerge を優先的に試行(複数変数パターン)
|
// 3. Phase 33-7: IfMerge を優先的に試行(複数変数パターン)
|
||||||
// IfMerge が成功すればそれを返す、失敗したら Select を試行
|
// IfMerge が成功すればそれを返す、失敗したら Select を試行
|
||||||
let if_merge_lowerer = if_merge::IfMergeLowerer::new(debug);
|
let if_merge_lowerer = if_merge::IfMergeLowerer::new(debug_level);
|
||||||
|
|
||||||
if if_merge_lowerer.can_lower_to_if_merge(func, block_id) {
|
if if_merge_lowerer.can_lower_to_if_merge(func, block_id) {
|
||||||
if let Some(result) = if_merge_lowerer.lower_if_to_if_merge(func, block_id) {
|
if let Some(result) = if_merge_lowerer.lower_if_to_if_merge(func, block_id) {
|
||||||
if debug {
|
if debug_level >= 1 {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[try_lower_if_to_joinir] IfMerge lowering used for {}",
|
"[try_lower_if_to_joinir] ✅ IfMerge lowering used for {}",
|
||||||
func.signature.name
|
func.signature.name
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -107,10 +125,10 @@ pub fn try_lower_if_to_joinir(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 4. IfMerge が失敗したら Select を試行(単一変数パターン)
|
// 4. IfMerge が失敗したら Select を試行(単一変数パターン)
|
||||||
let if_select_lowerer = if_select::IfSelectLowerer::new(debug);
|
let if_select_lowerer = if_select::IfSelectLowerer::new(debug_level);
|
||||||
|
|
||||||
if !if_select_lowerer.can_lower_to_select(func, block_id) {
|
if !if_select_lowerer.can_lower_to_select(func, block_id) {
|
||||||
if debug {
|
if debug_level >= 1 {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[try_lower_if_to_joinir] pattern not matched for {}",
|
"[try_lower_if_to_joinir] pattern not matched for {}",
|
||||||
func.signature.name
|
func.signature.name
|
||||||
@ -121,9 +139,9 @@ pub fn try_lower_if_to_joinir(
|
|||||||
|
|
||||||
let result = if_select_lowerer.lower_if_to_select(func, block_id);
|
let result = if_select_lowerer.lower_if_to_select(func, block_id);
|
||||||
|
|
||||||
if result.is_some() && debug {
|
if result.is_some() && debug_level >= 1 {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[try_lower_if_to_joinir] Select lowering used for {}",
|
"[try_lower_if_to_joinir] ✅ Select lowering used for {}",
|
||||||
func.signature.name
|
func.signature.name
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
72
tools/joinir_ab_test.sh
Normal file
72
tools/joinir_ab_test.sh
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Phase 33-8: A/B test automation for JoinIR lowering
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# tools/joinir_ab_test.sh <test_file.hako>
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# tools/joinir_ab_test.sh apps/tests/joinir_if_merge_simple.hako
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
test_case=$1 # e.g., "apps/tests/joinir_if_merge_simple.hako"
|
||||||
|
|
||||||
|
if [ ! -f "$test_case" ]; then
|
||||||
|
echo "❌ Test file not found: $test_case"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "🧪 Testing: $test_case"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Route A: Traditional if_phi
|
||||||
|
echo "=== Route A (if_phi) ==="
|
||||||
|
HAKO_JOINIR_IF_SELECT=0 \
|
||||||
|
NYASH_PARSER_STAGE3=1 \
|
||||||
|
HAKO_PARSER_STAGE3=1 \
|
||||||
|
./target/release/hakorune "$test_case" \
|
||||||
|
> /tmp/route_a.out 2>&1
|
||||||
|
route_a_rc=$?
|
||||||
|
echo "Route A RC: $route_a_rc"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Route B: JoinIR Select/IfMerge
|
||||||
|
echo "=== Route B (JoinIR) ==="
|
||||||
|
HAKO_JOINIR_IF_SELECT=1 \
|
||||||
|
HAKO_JOINIR_STAGE1=1 \
|
||||||
|
HAKO_JOINIR_DEBUG=1 \
|
||||||
|
NYASH_PARSER_STAGE3=1 \
|
||||||
|
HAKO_PARSER_STAGE3=1 \
|
||||||
|
./target/release/hakorune "$test_case" \
|
||||||
|
> /tmp/route_b.out 2>&1
|
||||||
|
route_b_rc=$?
|
||||||
|
echo "Route B RC: $route_b_rc"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Comparison
|
||||||
|
echo "=== 📊 Comparison ==="
|
||||||
|
|
||||||
|
# RC check
|
||||||
|
if [ $route_a_rc -eq $route_b_rc ]; then
|
||||||
|
echo "✅ RC matched: $route_a_rc"
|
||||||
|
else
|
||||||
|
echo "❌ RC mismatch: A=$route_a_rc, B=$route_b_rc"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Output check (ignore debug logs starting with '[')
|
||||||
|
if diff <(grep -v '^\[' /tmp/route_a.out) <(grep -v '^\[' /tmp/route_b.out); then
|
||||||
|
echo "✅ Output matched"
|
||||||
|
else
|
||||||
|
echo "❌ Output differs:"
|
||||||
|
diff <(grep -v '^\[' /tmp/route_a.out) <(grep -v '^\[' /tmp/route_b.out) || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extract lowering info from Route B
|
||||||
|
echo ""
|
||||||
|
echo "=== 🔍 Lowering Info ==="
|
||||||
|
grep -E "IfMerge|IfSelect|if_phi" /tmp/route_b.out || echo "⚠️ No lowering info found"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "🎉 A/B test PASSED for $test_case"
|
||||||
Reference in New Issue
Block a user