feat(joinir): Phase 259 P0 - Pattern8 BoolPredicateScan + Copy binding fix
Pattern8 (Boolean Predicate Scan) implementation for is_integer/1:
- New pattern detection for `loop + if not predicate() { return false }`
- JoinIR lowerer with main/loop_step/k_exit structure
- Me receiver passed as param (by-name 禁止)
Key fixes:
1. expr_result = Some(join_exit_value) (Pattern7 style)
2. Tail-call: dst: None (no extra Ret instruction)
3. instruction_rewriter: Add `&& is_loop_header_with_phi` check
- Pattern8 has no carriers → no PHIs → MUST generate Copy bindings
- Without this, ValueId(103/104/105) were undefined
Status: Copy instructions now generated correctly, but exit block
creation issue remains (next step: Step A-C in指示書).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -80,6 +80,7 @@ pub(in crate::mir::builder) mod pattern4_with_continue;
|
||||
pub(in crate::mir::builder) mod pattern5_infinite_early_exit; // Phase 131-11
|
||||
pub(in crate::mir::builder) mod pattern6_scan_with_init; // Phase 254 P0: index_of/find/contains pattern
|
||||
pub(in crate::mir::builder) mod pattern7_split_scan; // Phase 256 P0: split/tokenization with variable step
|
||||
pub(in crate::mir::builder) mod pattern8_scan_bool_predicate; // Phase 259 P0: boolean predicate scan (is_integer/is_valid)
|
||||
pub(in crate::mir::builder) mod pattern_pipeline;
|
||||
pub(in crate::mir::builder) mod router;
|
||||
pub(in crate::mir::builder) mod trim_loop_lowering; // Phase 180: Dedicated Trim/P5 lowering module
|
||||
|
||||
@ -0,0 +1,549 @@
|
||||
//! Pattern 8: Boolean Predicate Scan (is_integer/is_valid form)
|
||||
//!
|
||||
//! Phase 259 P0: Dedicated pattern for boolean predicate validation loops
|
||||
//!
|
||||
//! ## Pattern Structure
|
||||
//!
|
||||
//! ```nyash
|
||||
//! is_integer(s) {
|
||||
//! local i = start // Computed in prelude
|
||||
//! loop(i < s.length()) {
|
||||
//! if not this.is_digit(s.substring(i, i + 1)) {
|
||||
//! return false
|
||||
//! }
|
||||
//! i = i + 1
|
||||
//! }
|
||||
//! return true
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ## Detection Criteria (P0: Fixed Form Only)
|
||||
//!
|
||||
//! 1. Loop condition: `i < s.length()`
|
||||
//! 2. Loop body has if statement with:
|
||||
//! - Condition: `not this.method(...)` (UnaryOp::Not + MethodCall)
|
||||
//! - Then branch: `return false` (early exit)
|
||||
//! 3. Loop body has step: `i = i + 1`
|
||||
//! 4. Post-loop: `return true`
|
||||
//!
|
||||
//! ## vs Pattern 6
|
||||
//!
|
||||
//! - Pattern 6: Match scan (substring == needle → return i)
|
||||
//! - Pattern 8: Predicate scan (not is_digit → return false, else true)
|
||||
//! - Pattern 6: Returns integer (index or -1)
|
||||
//! - Pattern 8: Returns boolean (true/false)
|
||||
|
||||
use super::super::trace;
|
||||
use super::common::var;
|
||||
use crate::ast::{ASTNode, BinaryOperator, LiteralValue, UnaryOperator};
|
||||
use crate::mir::builder::MirBuilder;
|
||||
use crate::mir::ValueId;
|
||||
|
||||
/// Phase 259 P0: Extracted structure for boolean predicate scan
|
||||
#[derive(Debug, Clone)]
|
||||
struct BoolPredicateScanParts {
|
||||
/// Loop variable name (e.g., "i")
|
||||
loop_var: String,
|
||||
/// Haystack variable name (e.g., "s")
|
||||
haystack: String,
|
||||
/// Predicate method receiver (e.g., "this")
|
||||
predicate_receiver: String,
|
||||
/// Predicate method name (e.g., "is_digit")
|
||||
predicate_method: String,
|
||||
/// Step literal (P0: must be 1)
|
||||
step_lit: i64,
|
||||
}
|
||||
|
||||
/// Phase 259 P0: Detection for Pattern 8 (BoolPredicateScan)
|
||||
pub(crate) fn can_lower(_builder: &MirBuilder, ctx: &super::router::LoopPatternContext) -> bool {
|
||||
eprintln!("[pattern8/can_lower] Called for function: {}", ctx.func_name);
|
||||
match extract_bool_predicate_scan_parts(ctx.condition, ctx.body) {
|
||||
Ok(Some(_)) => {
|
||||
if ctx.debug {
|
||||
trace::trace().debug(
|
||||
"pattern8/can_lower",
|
||||
"accept: boolean predicate scan pattern extractable",
|
||||
);
|
||||
}
|
||||
true
|
||||
}
|
||||
Ok(None) => {
|
||||
if ctx.debug {
|
||||
trace::trace().debug(
|
||||
"pattern8/can_lower",
|
||||
"reject: not a boolean predicate scan pattern",
|
||||
);
|
||||
}
|
||||
false
|
||||
}
|
||||
Err(e) => {
|
||||
if ctx.debug {
|
||||
trace::trace().debug(
|
||||
"pattern8/can_lower",
|
||||
&format!("reject: extraction error: {}", e),
|
||||
);
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Phase 259 P0: Extract boolean predicate scan pattern parts
|
||||
///
|
||||
/// # P0 Restrictions (Fail-Fast)
|
||||
///
|
||||
/// - Loop condition: `i < s.length()` (forward only)
|
||||
/// - If condition: `not this.method(s.substring(i, i + 1))` (UnaryOp::Not)
|
||||
/// - Then branch: `return false` (Literal::Bool(false))
|
||||
/// - Step: `i = i + 1` (step_lit == 1)
|
||||
/// - Post-loop: `return true` (enforced by caller)
|
||||
fn extract_bool_predicate_scan_parts(
|
||||
condition: &ASTNode,
|
||||
body: &[ASTNode],
|
||||
) -> Result<Option<BoolPredicateScanParts>, String> {
|
||||
eprintln!("[pattern8/extract] Starting extraction");
|
||||
eprintln!("[pattern8/extract] Body statements: {}", body.len());
|
||||
|
||||
// 1. Check loop condition: i < s.length()
|
||||
let (loop_var, haystack) = match condition {
|
||||
ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Less,
|
||||
left,
|
||||
right,
|
||||
..
|
||||
} => {
|
||||
let loop_var = match left.as_ref() {
|
||||
ASTNode::Variable { name, .. } => name.clone(),
|
||||
_ => {
|
||||
eprintln!("[pattern8/extract] REJECT: loop condition left is not Variable");
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
|
||||
let haystack = match right.as_ref() {
|
||||
ASTNode::MethodCall {
|
||||
object, method, ..
|
||||
} if method == "length" => match object.as_ref() {
|
||||
ASTNode::Variable { name, .. } => name.clone(),
|
||||
_ => {
|
||||
eprintln!("[pattern8/extract] REJECT: length() object is not Variable");
|
||||
return Ok(None);
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
eprintln!("[pattern8/extract] REJECT: loop condition right is not .length()");
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
|
||||
(loop_var, haystack)
|
||||
}
|
||||
_ => {
|
||||
eprintln!("[pattern8/extract] REJECT: loop condition is not BinaryOp::Less");
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
eprintln!("[pattern8/extract] ✅ Loop condition OK: {} < {}.length()", loop_var, haystack);
|
||||
|
||||
// 2. Find if statement with predicate check and return false
|
||||
let mut predicate_receiver_opt = None;
|
||||
let mut predicate_method_opt = None;
|
||||
|
||||
eprintln!("[pattern8/extract] Step 2: Searching for predicate pattern in {} statements", body.len());
|
||||
for (i, stmt) in body.iter().enumerate() {
|
||||
eprintln!("[pattern8/extract] Statement {}: {:?}", i, stmt);
|
||||
if let ASTNode::If {
|
||||
condition: if_cond,
|
||||
then_body,
|
||||
..
|
||||
} = stmt
|
||||
{
|
||||
// Check if condition is: not this.method(...)
|
||||
if let ASTNode::UnaryOp {
|
||||
operator: UnaryOperator::Not,
|
||||
operand,
|
||||
..
|
||||
} = if_cond.as_ref()
|
||||
{
|
||||
// Operand must be MethodCall
|
||||
if let ASTNode::MethodCall {
|
||||
object,
|
||||
method,
|
||||
arguments,
|
||||
..
|
||||
} = operand.as_ref()
|
||||
{
|
||||
// Extract receiver (e.g., "me")
|
||||
// Phase 259 P0: Support both Variable and Me node
|
||||
// IMPORTANT: Me is registered as "me" in variable_map (not "this")
|
||||
let receiver = match object.as_ref() {
|
||||
ASTNode::Variable { name, .. } => name.clone(),
|
||||
ASTNode::Me { .. } => "me".to_string(), // Me is registered as "me" in MirBuilder
|
||||
_ => {
|
||||
eprintln!("[pattern8/extract] Receiver is not Variable or Me: {:?}", object);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// P0: Expect 1 argument: s.substring(i, i + 1)
|
||||
if arguments.len() != 1 {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Validate argument is substring call
|
||||
if let ASTNode::MethodCall {
|
||||
object: substr_obj,
|
||||
method: substr_method,
|
||||
arguments: substr_args,
|
||||
..
|
||||
} = &arguments[0]
|
||||
{
|
||||
if substr_method != "substring" {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Object must be haystack
|
||||
if let ASTNode::Variable { name, .. } = substr_obj.as_ref() {
|
||||
if name != &haystack {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Args: (i, i + 1)
|
||||
if substr_args.len() != 2 {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Arg 0: loop_var
|
||||
match &substr_args[0] {
|
||||
ASTNode::Variable { name, .. } if name == &loop_var => {}
|
||||
_ => continue,
|
||||
}
|
||||
|
||||
// Arg 1: loop_var + 1
|
||||
match &substr_args[1] {
|
||||
ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Add,
|
||||
left,
|
||||
right,
|
||||
..
|
||||
} => {
|
||||
// Left: loop_var
|
||||
match left.as_ref() {
|
||||
ASTNode::Variable { name, .. } if name == &loop_var => {}
|
||||
_ => continue,
|
||||
}
|
||||
|
||||
// Right: Literal(1)
|
||||
match right.as_ref() {
|
||||
ASTNode::Literal {
|
||||
value: LiteralValue::Integer(1),
|
||||
..
|
||||
} => {}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check then_body contains: return false
|
||||
if then_body.len() == 1 {
|
||||
if let ASTNode::Return { value, .. } = &then_body[0] {
|
||||
if let Some(ret_val) = value {
|
||||
if let ASTNode::Literal {
|
||||
value: LiteralValue::Bool(false),
|
||||
..
|
||||
} = ret_val.as_ref()
|
||||
{
|
||||
eprintln!("[pattern8/extract] ✅ Found predicate pattern: {}.{}", receiver, method);
|
||||
predicate_receiver_opt = Some(receiver);
|
||||
predicate_method_opt = Some(method.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if predicate_receiver_opt.is_none() {
|
||||
eprintln!("[pattern8/extract] REJECT: No predicate pattern found");
|
||||
}
|
||||
|
||||
let predicate_receiver = predicate_receiver_opt.ok_or_else(|| "No predicate pattern found")?;
|
||||
let predicate_method = predicate_method_opt.ok_or_else(|| "No predicate method found")?;
|
||||
|
||||
// 3. Check for step: i = i + 1
|
||||
let mut step_lit_opt = None;
|
||||
|
||||
eprintln!("[pattern8/extract] Step 3: Searching for step pattern ({} = {} + 1)", loop_var, loop_var);
|
||||
for stmt in body {
|
||||
if let ASTNode::Assignment { target, value, .. } = stmt {
|
||||
if let ASTNode::Variable { name: target_name, .. } = target.as_ref() {
|
||||
if target_name == &loop_var {
|
||||
if let ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Add,
|
||||
left,
|
||||
right,
|
||||
..
|
||||
} = value.as_ref()
|
||||
{
|
||||
if let ASTNode::Variable { name: left_name, .. } = left.as_ref() {
|
||||
if left_name == &loop_var {
|
||||
if let ASTNode::Literal {
|
||||
value: LiteralValue::Integer(lit),
|
||||
..
|
||||
} = right.as_ref()
|
||||
{
|
||||
eprintln!("[pattern8/extract] ✅ Found step pattern: {} = {} + {}", loop_var, loop_var, lit);
|
||||
step_lit_opt = Some(*lit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if step_lit_opt.is_none() {
|
||||
eprintln!("[pattern8/extract] REJECT: No step pattern found");
|
||||
}
|
||||
|
||||
let step_lit = step_lit_opt.ok_or_else(|| "No step pattern found")?;
|
||||
|
||||
// P0: Step must be 1
|
||||
if step_lit != 1 {
|
||||
eprintln!("[pattern8/extract] REJECT: Step is {}, expected 1", step_lit);
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
eprintln!("[pattern8/extract] ✅✅✅ ACCEPT: Pattern8 extraction successful!");
|
||||
eprintln!("[pattern8/extract] Parts: loop_var={}, haystack={}, predicate={}.{}, step={}",
|
||||
loop_var, haystack, predicate_receiver, predicate_method, step_lit);
|
||||
|
||||
Ok(Some(BoolPredicateScanParts {
|
||||
loop_var,
|
||||
haystack,
|
||||
predicate_receiver,
|
||||
predicate_method,
|
||||
step_lit,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Phase 259 P0: Lowering function for Pattern 8
|
||||
pub(crate) fn lower(
|
||||
builder: &mut MirBuilder,
|
||||
ctx: &super::router::LoopPatternContext,
|
||||
) -> Result<Option<ValueId>, String> {
|
||||
builder.cf_loop_pattern8_bool_predicate_impl(
|
||||
ctx.condition,
|
||||
ctx.body,
|
||||
ctx.func_name,
|
||||
ctx.debug,
|
||||
)
|
||||
}
|
||||
|
||||
impl MirBuilder {
|
||||
/// Phase 259 P0: Pattern 8 (BoolPredicateScan) implementation
|
||||
pub(crate) fn cf_loop_pattern8_bool_predicate_impl(
|
||||
&mut self,
|
||||
condition: &ASTNode,
|
||||
body: &[ASTNode],
|
||||
func_name: &str,
|
||||
debug: bool,
|
||||
) -> Result<Option<ValueId>, String> {
|
||||
use crate::mir::join_ir::lowering::join_value_space::JoinValueSpace;
|
||||
use crate::mir::join_ir::lowering::JoinInlineBoundaryBuilder;
|
||||
|
||||
let trace = trace::trace();
|
||||
|
||||
if debug {
|
||||
trace.debug(
|
||||
"pattern8/lower",
|
||||
&format!("Phase 259 P0: BoolPredicateScan lowering for {}", func_name),
|
||||
);
|
||||
}
|
||||
|
||||
// Step 1: Extract pattern parts
|
||||
let parts = extract_bool_predicate_scan_parts(condition, body)?
|
||||
.ok_or_else(|| format!("[pattern8] Not a boolean predicate scan pattern in {}", func_name))?;
|
||||
|
||||
if debug {
|
||||
trace.debug(
|
||||
"pattern8/lower",
|
||||
&format!(
|
||||
"Extracted: loop_var={}, haystack={}, predicate={}.{}, step={}",
|
||||
parts.loop_var, parts.haystack, parts.predicate_receiver, parts.predicate_method, parts.step_lit
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Step 2: Get host ValueIds for variables
|
||||
eprintln!("[pattern8/lower] variable_map contents:");
|
||||
for (name, vid) in &self.variable_ctx.variable_map {
|
||||
eprintln!("[pattern8/lower] {} -> {:?}", name, vid);
|
||||
}
|
||||
eprintln!("[pattern8/lower] Looking for receiver: {}", parts.predicate_receiver);
|
||||
|
||||
let s_host = self
|
||||
.variable_ctx
|
||||
.variable_map
|
||||
.get(&parts.haystack)
|
||||
.copied()
|
||||
.ok_or_else(|| format!("[pattern8] Variable {} not found", parts.haystack))?;
|
||||
|
||||
let i_host = self
|
||||
.variable_ctx
|
||||
.variable_map
|
||||
.get(&parts.loop_var)
|
||||
.copied()
|
||||
.ok_or_else(|| format!("[pattern8] Variable {} not found", parts.loop_var))?;
|
||||
|
||||
if debug {
|
||||
trace.debug(
|
||||
"pattern8/lower",
|
||||
&format!("Host ValueIds: s={:?}, i={:?}", s_host, i_host),
|
||||
);
|
||||
}
|
||||
|
||||
// Step 3: Create JoinModule
|
||||
let mut join_value_space = JoinValueSpace::new();
|
||||
use crate::mir::join_ir::lowering::scan_bool_predicate_minimal::lower_scan_bool_predicate_minimal;
|
||||
|
||||
let join_module = lower_scan_bool_predicate_minimal(
|
||||
&mut join_value_space,
|
||||
&parts.predicate_receiver,
|
||||
&parts.predicate_method,
|
||||
);
|
||||
|
||||
// Step 4: Build boundary (SSOT - use entry.params)
|
||||
use super::common::get_entry_function;
|
||||
let main_func = get_entry_function(&join_module, "pattern8")?;
|
||||
|
||||
// SSOT: Use actual params from JoinModule entry
|
||||
let join_inputs = main_func.params.clone();
|
||||
|
||||
// host_inputs in same order: [i, me, s] (alphabetical)
|
||||
// Phase 259 P0: me_host = receiver ValueId
|
||||
// IMPORTANT: Me receiver might not be in variable_map yet, so we use build_me_expression()
|
||||
let me_host = if parts.predicate_receiver == "me" {
|
||||
self.build_me_expression()?
|
||||
} else {
|
||||
self
|
||||
.variable_ctx
|
||||
.variable_map
|
||||
.get(&parts.predicate_receiver)
|
||||
.copied()
|
||||
.ok_or_else(|| format!("[pattern8] Receiver {} not found", parts.predicate_receiver))?
|
||||
};
|
||||
|
||||
let host_inputs = vec![i_host, me_host, s_host];
|
||||
|
||||
if debug {
|
||||
trace.debug(
|
||||
"pattern8/lower",
|
||||
&format!(
|
||||
"Boundary inputs: join_inputs={:?}, host_inputs={:?}",
|
||||
join_inputs, host_inputs
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Verify count consistency
|
||||
if join_inputs.len() != host_inputs.len() {
|
||||
return Err(format!(
|
||||
"[pattern8] Params count mismatch: join_inputs={}, host_inputs={}",
|
||||
join_inputs.len(), host_inputs.len()
|
||||
));
|
||||
}
|
||||
|
||||
// Step 5: Build exit_bindings (no carriers, only expr_result)
|
||||
// Pattern8 returns ret_bool directly (not loop variable)
|
||||
use crate::mir::join_ir::lowering::inline_boundary::LoopExitBinding;
|
||||
|
||||
let k_exit_func = join_module.require_function(
|
||||
crate::mir::join_ir::lowering::canonical_names::K_EXIT,
|
||||
"Pattern 8",
|
||||
);
|
||||
let join_exit_value = k_exit_func
|
||||
.params
|
||||
.first()
|
||||
.copied()
|
||||
.expect("k_exit must have parameter for exit value");
|
||||
|
||||
// Phase 259 P0: Allocate host ValueId for return value
|
||||
let result_host = self.next_value_id();
|
||||
self.type_ctx.value_types.insert(result_host, crate::mir::MirType::Bool);
|
||||
|
||||
// Phase 259 P0: exit_bindings contains ret_bool binding (Pattern7 style)
|
||||
// This allows remapper to map join_exit_value → result_host
|
||||
let result_exit_binding = LoopExitBinding {
|
||||
carrier_name: "ret_bool".to_string(), // Logical name for return value
|
||||
join_exit_value,
|
||||
host_slot: result_host,
|
||||
role: crate::mir::join_ir::lowering::carrier_info::CarrierRole::LoopState,
|
||||
};
|
||||
|
||||
let exit_bindings = vec![result_exit_binding];
|
||||
|
||||
// Step 6: Build boundary with expr_result
|
||||
use crate::mir::join_ir::lowering::carrier_info::CarrierInfo;
|
||||
|
||||
let carrier_info = CarrierInfo {
|
||||
loop_var_name: parts.loop_var.clone(),
|
||||
loop_var_id: i_host,
|
||||
carriers: vec![], // No carriers - Pattern8 uses expr_result only
|
||||
trim_helper: None,
|
||||
promoted_loopbodylocals: Vec::new(),
|
||||
#[cfg(feature = "normalized_dev")]
|
||||
promoted_bindings: std::collections::BTreeMap::new(),
|
||||
};
|
||||
|
||||
// Phase 259 P0: expr_result = join_exit_value (Pattern7 style)
|
||||
// Pattern8 returns boolean from k_exit, not loop variable
|
||||
|
||||
let boundary = JoinInlineBoundaryBuilder::new()
|
||||
.with_inputs(join_inputs, host_inputs)
|
||||
.with_exit_bindings(exit_bindings)
|
||||
.with_carrier_info(carrier_info)
|
||||
.with_expr_result(Some(join_exit_value)) // ✅ CRITICAL: Set expr_result to k_exit param
|
||||
.build();
|
||||
|
||||
if debug {
|
||||
trace.debug(
|
||||
"pattern8/lower",
|
||||
"Built boundary with expr_result (ret_bool from k_exit)",
|
||||
);
|
||||
}
|
||||
|
||||
// Step 7: Execute JoinIRConversionPipeline
|
||||
use super::conversion_pipeline::JoinIRConversionPipeline;
|
||||
let result = JoinIRConversionPipeline::execute(
|
||||
self,
|
||||
join_module,
|
||||
Some(&boundary),
|
||||
"pattern8",
|
||||
debug,
|
||||
)?;
|
||||
|
||||
eprintln!("[pattern8/lower] Pipeline execution complete, result: {:?}", result);
|
||||
|
||||
if debug {
|
||||
trace.debug(
|
||||
"pattern8/lower",
|
||||
&format!("Pattern 8 complete, result: {:?}", result),
|
||||
);
|
||||
}
|
||||
|
||||
// Pattern8 returns ret_bool (expr_result), not Void
|
||||
eprintln!("[pattern8/lower] Returning result: {:?}", result);
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
@ -203,6 +203,11 @@ pub(crate) static LOOP_PATTERNS: &[LoopPatternEntry] = &[
|
||||
detect: super::pattern7_split_scan::can_lower,
|
||||
lower: super::pattern7_split_scan::lower,
|
||||
},
|
||||
LoopPatternEntry {
|
||||
name: "Pattern8_BoolPredicateScan", // Phase 259 P0: boolean predicate scan (is_integer/is_valid)
|
||||
detect: super::pattern8_scan_bool_predicate::can_lower,
|
||||
lower: super::pattern8_scan_bool_predicate::lower,
|
||||
},
|
||||
LoopPatternEntry {
|
||||
name: "Pattern3_WithIfPhi",
|
||||
detect: super::pattern3_with_if_phi::can_lower,
|
||||
|
||||
Reference in New Issue
Block a user