Skip to content

Commit a681d2d

Browse files
committed
fix: resolve const generic loop bounds in Pattern1 loop detection via instance substs
ConstKind::Param cannot be resolved via try_to_scalar_int() in pre-monomorphized MIR. Pass Instance<'tcx> through detect_range_loop/try_build_range_loop_info/find_lt_locals_in_stmts and use instance.args.const_at(param.index).to_value().try_to_leaf() to materialize const generic bounds (e.g. `for kl in 0..KL` where KL: i32 is a const generic).
1 parent e3f224a commit a681d2d

1 file changed

Lines changed: 40 additions & 30 deletions

File tree

  • compiler/rustc_codegen_llvm/src/mlir/codegen/triton

compiler/rustc_codegen_llvm/src/mlir/codegen/triton/mod.rs

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,7 @@ fn compute_phi_join_locals<'tcx>(
550550
}
551551

552552
/// Detect all Range-based `for` loops in the MIR body.
553-
fn detect_range_loop<'tcx>(mir: &Body<'tcx>) -> Vec<RangeLoopInfo> {
553+
fn detect_range_loop<'tcx>(instance: Instance<'tcx>, mir: &Body<'tcx>) -> Vec<RangeLoopInfo> {
554554
use rustc_middle::mir::TerminatorKind;
555555

556556
let mut loops = Vec::new();
@@ -560,7 +560,7 @@ fn detect_range_loop<'tcx>(mir: &Body<'tcx>) -> Vec<RangeLoopInfo> {
560560
// Back edge: bb → target (target is the loop header)
561561
let header_bb = *target;
562562
let back_edge_bb = bb;
563-
if let Some(info) = try_build_range_loop_info(mir, header_bb, back_edge_bb) {
563+
if let Some(info) = try_build_range_loop_info(instance, mir, header_bb, back_edge_bb) {
564564
loops.push(info);
565565
}
566566
}
@@ -570,6 +570,7 @@ fn detect_range_loop<'tcx>(mir: &Body<'tcx>) -> Vec<RangeLoopInfo> {
570570
}
571571

572572
fn try_build_range_loop_info<'tcx>(
573+
instance: Instance<'tcx>,
573574
mir: &Body<'tcx>,
574575
header_bb: BasicBlock,
575576
back_edge_bb: BasicBlock,
@@ -592,32 +593,28 @@ fn try_build_range_loop_info<'tcx>(
592593
// Pattern 1: SwitchInt header with explicit Lt comparison (older Rust MIR).
593594
if let TerminatorKind::SwitchInt { discr, targets } = &header_data.terminator().kind {
594595
let cases: Vec<(u128, BasicBlock)> = targets.iter().collect();
595-
println!("[LOOP-DETECT] header={:?} back_edge={:?} SwitchInt cases={:?} otherwise={:?} discr={:?}",
596-
header_bb, back_edge_bb, cases, targets.otherwise(), discr);
597596
if cases.len() == 1 && cases[0].0 == 0 {
598597
let exit_bb = cases[0].1;
599598
let body_entry_bb = targets.otherwise();
600599
if let Operand::Move(p) | Operand::Copy(p) = discr {
601600
if p.projection.is_empty() {
602601
let discr_local = p.local;
603-
if let Some((counter_local, bl)) =
604-
find_lt_locals_in_stmts(&header_data.statements, discr_local)
602+
if let Some((counter_local, bl, bc)) =
603+
find_lt_locals_in_stmts(&header_data.statements, discr_local, instance)
605604
{
606-
println!("[LOOP-DETECT] Pattern1 detected: counter={:?} bound_local={:?}", counter_local, bl);
607605
break 'detect HeaderInfo {
608606
body_entry_bb,
609607
exit_bb,
610608
counter_local_hint: Some(counter_local),
611-
bound_local: Some(bl),
612-
bound_const: None,
609+
bound_local: bl,
610+
bound_const: bc,
613611
switch_bb: None,
614612
next_result_local: None,
615613
};
616614
}
617615
}
618616
}
619617
}
620-
println!("[LOOP-DETECT] FAIL Pattern1: cases={:?}", cases);
621618
}
622619

623620
// Pattern 2: Call header (Range::next) followed by SwitchInt on discriminant (Rust 1.93+).
@@ -627,8 +624,6 @@ fn try_build_range_loop_info<'tcx>(
627624
let switch_data = &mir.basic_blocks[*switch_bb_cand];
628625
if let TerminatorKind::SwitchInt { targets, .. } = &switch_data.terminator().kind {
629626
let cases: Vec<(u128, BasicBlock)> = targets.iter().collect();
630-
println!("[LOOP-DETECT] header={:?} back_edge={:?} Call+SwitchInt cases={:?} otherwise={:?}",
631-
header_bb, back_edge_bb, cases, targets.otherwise());
632627
// Discriminant 0 = None (exit), discriminant 1 = Some (body)
633628
if cases.len() == 2 && cases[0].0 == 0 && cases[1].0 == 1
634629
&& destination.projection.is_empty()
@@ -637,7 +632,6 @@ fn try_build_range_loop_info<'tcx>(
637632
let body_entry_bb = cases[1].1;
638633
let next_result_local = destination.local;
639634
if let Some((bc, bl)) = find_range_bound(mir, header_bb) {
640-
println!("[LOOP-DETECT] Pattern2 detected: bound_const={:?} bound_local={:?}", bc, bl);
641635
break 'detect HeaderInfo {
642636
body_entry_bb,
643637
exit_bb,
@@ -650,37 +644,30 @@ fn try_build_range_loop_info<'tcx>(
650644
}
651645
}
652646
}
653-
println!("[LOOP-DETECT] FAIL Pattern2: switch_bb={:?}", switch_bb_cand);
654647
}
655648

656-
println!("[LOOP-DETECT] header={:?} back_edge={:?}: no pattern matched", header_bb, back_edge_bb);
657649
return None;
658650
};
659651

660652
// Collect body blocks in topological (execution) order
661653
let body_bbs = collect_body_blocks_ordered(mir, hinfo.body_entry_bb, header_bb);
662-
println!("[LOOP-DETECT] body_bbs={:?} back_edge_in_body={}", body_bbs, body_bbs.contains(&back_edge_bb));
663654
if !body_bbs.contains(&back_edge_bb) {
664655
return None;
665656
}
666657

667658
// Find the induction local: extracted from Option::Some via downcast projection
668-
let induction_result = find_induction_local_in_bbs(mir, &body_bbs);
669-
println!("[LOOP-DETECT] induction_local={:?}", induction_result);
670-
let induction_local = induction_result?;
659+
let induction_local = find_induction_local_in_bbs(mir, &body_bbs)?;
671660

672661
let counter_local = hinfo.counter_local_hint.unwrap_or(induction_local);
673662

674663
// Find loop-carried locals (used before assigned in topological order).
675664
let mut iter_carry_locals = find_iter_carry_locals(mir, &body_bbs);
676-
println!("[LOOP-DETECT] iter_carry_locals (before filter)={:?}", iter_carry_locals);
677665

678666
// For the Call-header pattern, exclude the Range::next result local (next_result_local)
679667
// from iter-carry: it is synthesised by scf.for, not a user-defined loop-carried value.
680668
if let Some(nrl) = hinfo.next_result_local {
681669
iter_carry_locals.retain(|&l| l != nrl);
682670
}
683-
println!("[LOOP-DETECT] iter_carry_locals (final)={:?}", iter_carry_locals);
684671

685672
Some(RangeLoopInfo {
686673
header_bb,
@@ -744,11 +731,14 @@ fn try_const_operand_as_i64(c: &ConstOperand<'_>) -> Option<i64> {
744731
c.const_.try_to_scalar_int().map(|s| s.to_bits_unchecked() as i64)
745732
}
746733

747-
/// Find the Lt statement that assigns `discr_local` and extract (counter_local, bound_local).
734+
/// Find the Lt statement that assigns `discr_local` and extract
735+
/// `(counter_local, bound_local_or_const)` where the bound is either a local or a constant.
736+
/// Returns `(counter, Some(bound_local), None)` or `(counter, None, Some(bound_const))`.
748737
fn find_lt_locals_in_stmts<'tcx>(
749738
stmts: &[Statement<'tcx>],
750739
discr_local: Local,
751-
) -> Option<(Local, Local)> {
740+
instance: Instance<'tcx>,
741+
) -> Option<(Local, Option<Local>, Option<i64>)> {
752742
for stmt in stmts {
753743
if let StatementKind::Assign(assign) = &stmt.kind {
754744
let (dest, rvalue) = assign.as_ref();
@@ -759,14 +749,34 @@ fn find_lt_locals_in_stmts<'tcx>(
759749
Operand::Move(p) | Operand::Copy(p) if p.projection.is_empty() => p.local,
760750
_ => return None,
761751
};
762-
let bound_local = match rhs {
763-
Operand::Move(p) | Operand::Copy(p) if p.projection.is_empty() => p.local,
764-
_ => return None,
765-
};
766-
// Resolve the counter_copy (might be a copy of the real counter)
767752
let counter_local = find_copy_source_in_stmts(stmts, counter_copy)
768753
.unwrap_or(counter_copy);
769-
return Some((counter_local, bound_local));
754+
match rhs {
755+
Operand::Move(p) | Operand::Copy(p) if p.projection.is_empty() => {
756+
return Some((counter_local, Some(p.local), None));
757+
}
758+
Operand::Constant(c) => {
759+
// Try simple scalar first (works for literal constants)
760+
if let Some(v) = try_const_operand_as_i64(c) {
761+
return Some((counter_local, None, Some(v)));
762+
}
763+
// Handle ConstKind::Param (const generic — resolve via instance substs)
764+
use rustc_middle::mir::Const as MirConst;
765+
if let MirConst::Ty(ty, const_val) = c.const_ {
766+
if ty.is_integral() {
767+
if let ConstKind::Param(param) = const_val.kind() {
768+
let subst = instance.args.const_at(param.index as usize);
769+
let cv = subst.to_value();
770+
if let Some(si) = cv.try_to_leaf() {
771+
return Some((counter_local, None, Some(si.to_bits_unchecked() as i64)));
772+
}
773+
}
774+
}
775+
}
776+
return None;
777+
}
778+
_ => return None,
779+
}
770780
}
771781
}
772782
}
@@ -1431,7 +1441,7 @@ impl<'a> TritonCodegen<'a> {
14311441

14321442
// Detect all Range-based `for` loops. Loop body blocks live in the scf.for region, not
14331443
// in the function region, so we skip creating MLIR blocks for them here.
1434-
let loop_infos = detect_range_loop(mir);
1444+
let loop_infos = detect_range_loop(*instance, mir);
14351445

14361446
// The set of MIR blocks that belong to any scf.for region.
14371447
let mut loop_region_blocks: HashSet<BasicBlock> = HashSet::new();

0 commit comments

Comments
 (0)