Skip to content

Commit 27aca44

Browse files
committed
Fix island cycle handling and preserve IdVec bounds
1 parent b8fe72b commit 27aca44

File tree

3 files changed

+72
-13
lines changed

3 files changed

+72
-13
lines changed

libs/@local/hashql/core/src/id/vec.rs

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use core::{
66
fmt::{self, Debug},
77
hash::{Hash, Hasher},
88
marker::PhantomData,
9-
ops::{Deref, DerefMut, RangeBounds},
9+
ops::{Bound, Deref, DerefMut, RangeBounds},
1010
slice,
1111
};
1212

@@ -510,8 +510,16 @@ where
510510
where
511511
T: Copy,
512512
{
513-
let start = src.start_bound().copied().map(Id::as_usize);
514-
let end = src.end_bound().copied().map(Id::as_usize);
513+
let start = match src.start_bound() {
514+
Bound::Included(&bound) => Bound::Included(bound.as_usize()),
515+
Bound::Excluded(&bound) => Bound::Excluded(bound.as_usize()),
516+
Bound::Unbounded => Bound::Unbounded,
517+
};
518+
let end = match src.end_bound() {
519+
Bound::Included(&bound) => Bound::Included(bound.as_usize()),
520+
Bound::Excluded(&bound) => Bound::Excluded(bound.as_usize()),
521+
Bound::Unbounded => Bound::Unbounded,
522+
};
515523

516524
self.raw.copy_within((start, end), dst.as_usize());
517525
}
@@ -796,3 +804,23 @@ where
796804
Self::from_raw(Vec::from_iter_in(iter, alloc))
797805
}
798806
}
807+
808+
#[cfg(test)]
809+
mod tests {
810+
use super::IdVec;
811+
use crate::id::{Id as _, newtype};
812+
813+
newtype!(#[id(crate = crate)] struct TestId(u32 is 0..=32));
814+
815+
#[test]
816+
fn copy_within_preserves_inclusive_end_bound() {
817+
let mut vec = IdVec::<TestId, i32>::from_raw(alloc::vec![10, 20, 30]);
818+
819+
vec.copy_within(
820+
TestId::from_usize(1)..=TestId::from_usize(1),
821+
TestId::from_usize(0),
822+
);
823+
824+
assert_eq!(vec.as_slice().as_raw(), &[20, 20, 30]);
825+
}
826+
}

libs/@local/hashql/mir/src/pass/execution/island/graph/mod.rs

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#[cfg(test)]
2121
pub(crate) mod tests;
2222

23-
use alloc::alloc::Global;
23+
use alloc::{alloc::Global, collections::VecDeque};
2424
use core::{
2525
alloc::Allocator,
2626
ops::{Index, IndexMut},
@@ -29,11 +29,10 @@ use core::{
2929
use hashql_core::{
3030
debug_panic,
3131
graph::{
32-
DirectedGraph, EdgeId, LinkedGraph, NodeId, Predecessors, Successors, Traverse as _,
32+
DirectedGraph, EdgeId, LinkedGraph, NodeId, Predecessors, Successors,
3333
algorithms::{Dominators, dominators},
3434
linked::Edge,
3535
},
36-
heap::CollectIn as _,
3736
id::{
3837
HasId as _, Id as _,
3938
bit_vec::{BitMatrix, DenseBitSet},
@@ -243,12 +242,38 @@ impl<A: Allocator> IslandGraph<A> {
243242
where
244243
S: Allocator + Clone,
245244
{
246-
let mut topo: Vec<IslandId, _> = self
247-
.inner
248-
.depth_first_forest_post_order()
249-
.map(|node| IslandId::new(node.as_u32()))
250-
.collect_in(scratch.clone());
251-
topo.reverse();
245+
#[expect(clippy::cast_possible_truncation)]
246+
let node_count = self.node_count();
247+
let mut in_degree = IslandVec::from_elem_in(0_u32, node_count, scratch.clone());
248+
for (island_id, _) in self.iter_nodes() {
249+
in_degree[island_id] = self.predecessors(island_id).count() as u32;
250+
}
251+
252+
let mut queue: VecDeque<IslandId, _> = VecDeque::new_in(scratch.clone());
253+
for (island_id, _) in self.iter_nodes() {
254+
if in_degree[island_id] == 0 {
255+
queue.push_back(island_id);
256+
}
257+
}
258+
259+
let mut topo = Vec::with_capacity_in(node_count, scratch.clone());
260+
while let Some(island_id) = queue.pop_front() {
261+
topo.push(island_id);
262+
263+
for successor in self.successors(island_id) {
264+
in_degree[successor] -= 1;
265+
266+
if in_degree[successor] == 0 {
267+
queue.push_back(successor);
268+
}
269+
}
270+
}
271+
272+
assert_eq!(
273+
topo.len(),
274+
node_count,
275+
"island requirement resolution requires acyclic control flow",
276+
);
252277

253278
let start = self.lookup[BasicBlockId::START];
254279

@@ -379,7 +404,7 @@ impl<'graph, A: Allocator, S: Allocator + Clone> RequirementResolver<'graph, A,
379404
}
380405

381406
fn resolve(mut self, topo: &[IslandId]) {
382-
// Iterate in reverse for topological order
407+
// Iterate in topological order so dominators are processed before dependents.
383408
for &island_id in topo {
384409
let island = &self.graph[island_id];
385410
let IslandKind::Exec(_) = &island.kind else {

libs/@local/hashql/mir/src/pass/execution/island/schedule/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,12 @@ impl<A: Allocator> IslandGraph<A> {
122122
}
123123
}
124124

125+
assert_eq!(
126+
entries.len(),
127+
node_count,
128+
"island schedule requires acyclic control flow",
129+
);
130+
125131
entries.sort_by_key(|entry| entry.level);
126132
IslandSchedule { entries }
127133
}

0 commit comments

Comments
 (0)