feat(joinir): Phase 170-C-1 Carrier name heuristic for shape detection
Add detect_with_carrier_name() to improve CaseALoweringShape detection accuracy by using carrier variable names as a heuristic. Since LoopUpdateAnalyzer operates at AST level (not accessible from MIR), use carrier naming conventions instead: - Typical index names (i, e, idx, pos, start, end) → StringExamination - Other names (result, items, defs) → ArrayAccumulation This reduces Generic fallback cases for single-carrier loops. Changes: - case_a_lowering_shape.rs: Add detect_with_carrier_name(), is_typical_index_name() - loop_to_join.rs: Extract progress_carrier name, call new detection function Phase 170-C-2 can add MIR-based update pattern analysis for higher accuracy. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -82,7 +82,7 @@ pub enum CaseALoweringShape {
|
||||
}
|
||||
|
||||
impl CaseALoweringShape {
|
||||
/// Detect lowering shape from LoopFeatures
|
||||
/// Detect lowering shape from LoopFeatures (legacy, use detect_with_updates when possible)
|
||||
///
|
||||
/// # Phase 170-A Design Principle
|
||||
///
|
||||
@ -96,9 +96,8 @@ impl CaseALoweringShape {
|
||||
/// - Multiple carriers (2+) → likely IterationWithAccumulation
|
||||
/// - has_break/has_continue → affects Case-A eligibility
|
||||
///
|
||||
/// # Phase 170-B Future Work
|
||||
/// - Analyze loop body AST for more precise classification
|
||||
/// - Distinguish StringExamination vs ArrayAccumulation
|
||||
/// # Phase 170-C Future Work
|
||||
/// - Use detect_with_updates() for better single-carrier classification
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `features` - LoopFeatures (structure-based, name-agnostic)
|
||||
@ -128,7 +127,7 @@ impl CaseALoweringShape {
|
||||
}
|
||||
1 => {
|
||||
// Single carrier: could be StringExamination or ArrayAccumulation
|
||||
// Further distinction requires analyzing loop body (Phase 170-B)
|
||||
// Further distinction requires analyzing loop body (Phase 170-C)
|
||||
// For now, return Generic to allow both paths to be tried
|
||||
CaseALoweringShape::Generic
|
||||
}
|
||||
@ -140,6 +139,83 @@ impl CaseALoweringShape {
|
||||
}
|
||||
}
|
||||
|
||||
/// Phase 170-C-1: Carrier pattern を使った精度向上版
|
||||
///
|
||||
/// carrier_count == 1 の場合に carrier 名パターンで StringExamination vs ArrayAccumulation を区別
|
||||
///
|
||||
/// # Design Notes
|
||||
///
|
||||
/// 本来は LoopUpdateAnalyzer を使って AST レベルの更新式を解析する予定だったが、
|
||||
/// loop_to_join.rs は MIR レベルで動作するため AST にアクセスできない。
|
||||
///
|
||||
/// そのため、Phase 170-C-1 では以下の簡易的なヒューリスティックを使用:
|
||||
/// - progress carrier の名前が 'i', 'e', 'idx' などの典型的なインデックス名 → StringExamination
|
||||
/// - それ以外 → ArrayAccumulation
|
||||
///
|
||||
/// # Future Work (Phase 170-C-2+)
|
||||
///
|
||||
/// - MIR 命令を解析して更新パターンを抽出(BinOp の定数加算パターンなど)
|
||||
/// - より正確な分類を実現
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `features` - LoopFeatures (structure-based)
|
||||
/// * `carrier_count` - Number of carrier variables
|
||||
/// * `has_progress_carrier` - Whether progress carrier exists
|
||||
/// * `progress_carrier_name` - Name of progress carrier (if available)
|
||||
///
|
||||
/// # Returns
|
||||
/// More precise CaseALoweringShape classification
|
||||
pub fn detect_with_carrier_name(
|
||||
features: &crate::mir::loop_pattern_detection::LoopFeatures,
|
||||
carrier_count: usize,
|
||||
has_progress_carrier: bool,
|
||||
progress_carrier_name: Option<&str>,
|
||||
) -> Self {
|
||||
// Case-A requirement: must have a progress carrier
|
||||
if !has_progress_carrier {
|
||||
return CaseALoweringShape::NotCaseA;
|
||||
}
|
||||
|
||||
// Case-A requirement: no complex control flow (continue)
|
||||
if features.has_continue {
|
||||
return CaseALoweringShape::NotCaseA;
|
||||
}
|
||||
|
||||
match carrier_count {
|
||||
0 => CaseALoweringShape::NotCaseA,
|
||||
1 => {
|
||||
// Phase 170-C-1: carrier 名パターンで StringExamination vs ArrayAccumulation を区別
|
||||
if let Some(name) = progress_carrier_name {
|
||||
if Self::is_typical_index_name(name) {
|
||||
// 'i', 'e', 'idx' などの典型的なインデックス名 → StringExamination (skip/trim 系)
|
||||
CaseALoweringShape::StringExamination
|
||||
} else {
|
||||
// それ以外 → ArrayAccumulation
|
||||
CaseALoweringShape::ArrayAccumulation
|
||||
}
|
||||
} else {
|
||||
// carrier 名が不明な場合は Generic(従来通り)
|
||||
CaseALoweringShape::Generic
|
||||
}
|
||||
}
|
||||
2.. => CaseALoweringShape::IterationWithAccumulation,
|
||||
}
|
||||
}
|
||||
|
||||
/// Typical index variable name detection
|
||||
///
|
||||
/// StringExamination パターン(skip/trim)で使われる典型的なインデックス名:
|
||||
/// - 'i', 'e', 'idx', 'pos', 'start', 'end'
|
||||
///
|
||||
/// ArrayAccumulation パターンは通常:
|
||||
/// - より意味のある名前 ('result', 'items', 'defs' など)
|
||||
fn is_typical_index_name(name: &str) -> bool {
|
||||
matches!(
|
||||
name,
|
||||
"i" | "e" | "idx" | "index" | "pos" | "position" | "start" | "end"
|
||||
)
|
||||
}
|
||||
|
||||
/// Legacy wrapper: Detect from LoopScopeShape (deprecated, use detect_from_features)
|
||||
///
|
||||
/// Phase 170-A: Kept for backward compatibility during transition.
|
||||
|
||||
@ -382,14 +382,40 @@ impl LoopToJoinLowerer {
|
||||
//
|
||||
// This enables gradual migration: existing name-based code continues to work,
|
||||
// while new patterns can be added purely by structure detection.
|
||||
#[allow(deprecated)]
|
||||
let shape = CaseALoweringShape::detect(&scope);
|
||||
|
||||
// Phase 170-C-1: Use carrier name-based detection for improved accuracy
|
||||
// Extract progress carrier name from scope
|
||||
let progress_carrier_name = scope.progress_carrier.as_deref();
|
||||
|
||||
// Construct minimal LoopFeatures from scope (for now)
|
||||
// TODO: Pass real LoopFeatures from LoopPatternDetection when available
|
||||
let stub_features = crate::mir::loop_pattern_detection::LoopFeatures {
|
||||
has_break: false, // Unknown at this level
|
||||
has_continue: false, // Unknown at this level
|
||||
has_if: false,
|
||||
has_if_else_phi: false,
|
||||
carrier_count: scope.carriers.len(),
|
||||
break_count: 0,
|
||||
continue_count: 0,
|
||||
};
|
||||
|
||||
let has_progress_carrier = scope.progress_carrier.is_some();
|
||||
let carrier_count = scope.carriers.len();
|
||||
|
||||
// Phase 170-C-1: Use new carrier name-based detection
|
||||
let shape = CaseALoweringShape::detect_with_carrier_name(
|
||||
&stub_features,
|
||||
carrier_count,
|
||||
has_progress_carrier,
|
||||
progress_carrier_name,
|
||||
);
|
||||
|
||||
if self.debug {
|
||||
eprintln!(
|
||||
"[LoopToJoinLowerer] Phase 170-A: shape={:?}, name={:?}",
|
||||
"[LoopToJoinLowerer] Phase 170-C-1: shape={:?}, name={:?}, carrier={:?}",
|
||||
shape.name(),
|
||||
name
|
||||
name,
|
||||
progress_carrier_name
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user