1use std::collections::HashMap;
6
7use super::types::{
8 AffineMap, CmpfPred, CmpiPred, MLIRAnalysisCache, MLIRConstantFoldingHelper, MLIRDepGraph,
9 MLIRDominatorTree, MLIRExtCache, MLIRExtConstFolder, MLIRExtDepGraph, MLIRExtDomTree,
10 MLIRExtLiveness, MLIRExtPassConfig, MLIRExtPassPhase, MLIRExtPassRegistry, MLIRExtPassStats,
11 MLIRExtWorklist, MLIRLivenessInfo, MLIRPassConfig, MLIRPassPhase, MLIRPassRegistry,
12 MLIRPassStats, MLIRWorklist, MlirAttr, MlirBackend, MlirBlock, MlirBuilder, MlirDialect,
13 MlirFunc, MlirGlobal, MlirModule, MlirRegion, MlirType, MlirValue, SsaCounter,
14};
15
16#[cfg(test)]
17mod tests {
18 use super::*;
19 #[test]
20 pub(super) fn test_mlir_type_integer_display() {
21 assert_eq!(MlirType::Integer(64, false).to_string(), "i64");
22 assert_eq!(MlirType::Integer(32, false).to_string(), "i32");
23 assert_eq!(MlirType::Integer(1, false).to_string(), "i1");
24 }
25 #[test]
26 pub(super) fn test_mlir_type_signed_integer_display() {
27 assert_eq!(MlirType::Integer(32, true).to_string(), "si32");
28 }
29 #[test]
30 pub(super) fn test_mlir_type_float_display() {
31 assert_eq!(MlirType::Float(32).to_string(), "f32");
32 assert_eq!(MlirType::Float(64).to_string(), "f64");
33 assert_eq!(MlirType::Float(16).to_string(), "f16");
34 }
35 #[test]
36 pub(super) fn test_mlir_type_index() {
37 assert_eq!(MlirType::Index.to_string(), "index");
38 }
39 #[test]
40 pub(super) fn test_mlir_type_none() {
41 assert_eq!(MlirType::NoneType.to_string(), "none");
42 }
43 #[test]
44 pub(super) fn test_mlir_type_tensor() {
45 let ty = MlirType::Tensor(vec![2, 3], Box::new(MlirType::Float(32)));
46 assert_eq!(ty.to_string(), "tensor<2x3xf32>");
47 }
48 #[test]
49 pub(super) fn test_mlir_type_tensor_dynamic() {
50 let ty = MlirType::Tensor(vec![-1, 4], Box::new(MlirType::Integer(64, false)));
51 assert_eq!(ty.to_string(), "tensor<?x4xi64>");
52 }
53 #[test]
54 pub(super) fn test_mlir_type_vector() {
55 let ty = MlirType::Vector(vec![4], Box::new(MlirType::Float(32)));
56 assert_eq!(ty.to_string(), "vector<4xf32>");
57 }
58 #[test]
59 pub(super) fn test_mlir_type_memref() {
60 let ty = MlirType::MemRef(
61 Box::new(MlirType::Float(64)),
62 vec![10, 20],
63 AffineMap::Constant,
64 );
65 assert!(ty.to_string().starts_with("memref<10x20xf64"));
66 }
67 #[test]
68 pub(super) fn test_mlir_type_tuple() {
69 let ty = MlirType::Tuple(vec![MlirType::Integer(32, false), MlirType::Float(64)]);
70 assert_eq!(ty.to_string(), "tuple<i32, f64>");
71 }
72 #[test]
73 pub(super) fn test_mlir_type_func_type() {
74 let ty = MlirType::FuncType(
75 vec![MlirType::Integer(64, false), MlirType::Integer(64, false)],
76 vec![MlirType::Integer(64, false)],
77 );
78 assert_eq!(ty.to_string(), "(i64, i64) -> i64");
79 }
80 #[test]
81 pub(super) fn test_mlir_value_numbered() {
82 let v = MlirValue::numbered(0, MlirType::Integer(64, false));
83 assert_eq!(v.to_string(), "%0");
84 }
85 #[test]
86 pub(super) fn test_mlir_value_named() {
87 let v = MlirValue::named("arg0", MlirType::Float(32));
88 assert_eq!(v.to_string(), "%arg0");
89 }
90 #[test]
91 pub(super) fn test_attr_integer() {
92 let attr = MlirAttr::Integer(42, MlirType::Integer(64, false));
93 assert_eq!(attr.to_string(), "42 : i64");
94 }
95 #[test]
96 pub(super) fn test_attr_string() {
97 let attr = MlirAttr::Str("hello".to_string());
98 assert_eq!(attr.to_string(), "\"hello\"");
99 }
100 #[test]
101 pub(super) fn test_attr_string_escaping() {
102 let attr = MlirAttr::Str("say \"hi\"".to_string());
103 assert!(attr.to_string().contains("\\\""));
104 }
105 #[test]
106 pub(super) fn test_attr_symbol() {
107 let attr = MlirAttr::Symbol("add".to_string());
108 assert_eq!(attr.to_string(), "@add");
109 }
110 #[test]
111 pub(super) fn test_attr_array() {
112 let attr = MlirAttr::Array(vec![
113 MlirAttr::Integer(1, MlirType::Integer(32, false)),
114 MlirAttr::Integer(2, MlirType::Integer(32, false)),
115 ]);
116 assert!(attr.to_string().starts_with('['));
117 assert!(attr.to_string().ends_with(']'));
118 }
119 #[test]
120 pub(super) fn test_attr_dict() {
121 let attr = MlirAttr::Dict(vec![("key".to_string(), MlirAttr::Bool(true))]);
122 let s = attr.to_string();
123 assert!(s.contains("key"));
124 assert!(s.contains("true"));
125 }
126 #[test]
127 pub(super) fn test_builder_const_int() {
128 let mut b = MlirBuilder::new();
129 let v = b.const_int(42, 64);
130 assert_eq!(v.name, "0");
131 assert!(matches!(v.ty, MlirType::Integer(64, false)));
132 let ops = b.take_ops();
133 assert_eq!(ops.len(), 1);
134 assert_eq!(ops[0].op_name, "arith.constant");
135 }
136 #[test]
137 pub(super) fn test_builder_const_float() {
138 let mut b = MlirBuilder::new();
139 let v = b.const_float(3.14, 64);
140 assert!(matches!(v.ty, MlirType::Float(64)));
141 let ops = b.take_ops();
142 assert_eq!(ops[0].op_name, "arith.constant");
143 }
144 #[test]
145 pub(super) fn test_builder_addi() {
146 let mut b = MlirBuilder::new();
147 let lhs = MlirValue::named("x", MlirType::Integer(64, false));
148 let rhs = MlirValue::named("y", MlirType::Integer(64, false));
149 let result = b.addi(lhs, rhs);
150 assert!(matches!(result.ty, MlirType::Integer(64, false)));
151 let ops = b.take_ops();
152 assert_eq!(ops[0].op_name, "arith.addi");
153 }
154 #[test]
155 pub(super) fn test_builder_muli() {
156 let mut b = MlirBuilder::new();
157 let lhs = MlirValue::named("a", MlirType::Integer(32, false));
158 let rhs = MlirValue::named("b", MlirType::Integer(32, false));
159 let _ = b.muli(lhs, rhs);
160 let ops = b.take_ops();
161 assert_eq!(ops[0].op_name, "arith.muli");
162 }
163 #[test]
164 pub(super) fn test_builder_cmpi() {
165 let mut b = MlirBuilder::new();
166 let lhs = MlirValue::named("a", MlirType::Integer(64, false));
167 let rhs = MlirValue::named("b", MlirType::Integer(64, false));
168 let result = b.cmpi(CmpiPred::Slt, lhs, rhs);
169 assert!(matches!(result.ty, MlirType::Integer(1, false)));
170 let ops = b.take_ops();
171 assert_eq!(ops[0].op_name, "arith.cmpi");
172 }
173 #[test]
174 pub(super) fn test_builder_math_sin() {
175 let mut b = MlirBuilder::new();
176 let v = MlirValue::named("x", MlirType::Float(64));
177 let _ = b.sin(v);
178 let ops = b.take_ops();
179 assert_eq!(ops[0].op_name, "math.sin");
180 }
181 #[test]
182 pub(super) fn test_builder_return_op() {
183 let mut b = MlirBuilder::new();
184 let v = MlirValue::named("result", MlirType::Integer(64, false));
185 b.return_op(vec![v]);
186 let ops = b.take_ops();
187 assert_eq!(ops[0].op_name, "func.return");
188 }
189 #[test]
190 pub(super) fn test_builder_call() {
191 let mut b = MlirBuilder::new();
192 let arg = MlirValue::named("x", MlirType::Integer(64, false));
193 let results = b.call("foo", vec![arg], vec![MlirType::Integer(64, false)]);
194 assert_eq!(results.len(), 1);
195 let ops = b.take_ops();
196 assert_eq!(ops[0].op_name, "func.call");
197 }
198 #[test]
199 pub(super) fn test_module_emit_empty() {
200 let module = MlirModule::new();
201 let output = module.emit();
202 assert!(output.starts_with("module {"));
203 assert!(output.ends_with("}\n"));
204 }
205 #[test]
206 pub(super) fn test_module_emit_named() {
207 let module = MlirModule::named("my_module");
208 let output = module.emit();
209 assert!(output.starts_with("module @my_module {"));
210 }
211 #[test]
212 pub(super) fn test_module_emit_func() {
213 let mut module = MlirModule::new();
214 let int_ty = MlirType::Integer(64, false);
215 let mut builder = MlirBuilder::new();
216 let arg0 = MlirValue::named("arg0", int_ty.clone());
217 let arg1 = MlirValue::named("arg1", int_ty.clone());
218 let sum = builder.addi(arg0.clone(), arg1.clone());
219 builder.return_op(vec![sum]);
220 let block = MlirBlock::entry(vec![arg0, arg1], builder.take_ops());
221 let func = MlirFunc::new(
222 "add",
223 vec![
224 ("arg0".to_string(), int_ty.clone()),
225 ("arg1".to_string(), int_ty.clone()),
226 ],
227 vec![int_ty],
228 MlirRegion::single_block(block),
229 );
230 module.add_function(func);
231 let output = module.emit();
232 assert!(output.contains("func.func @add"));
233 assert!(output.contains("arith.addi"));
234 assert!(output.contains("func.return"));
235 }
236 #[test]
237 pub(super) fn test_backend_compile_add_func() {
238 let mut backend = MlirBackend::new();
239 backend.compile_add_func("add64", 64);
240 let output = backend.emit_module();
241 assert!(output.contains("module {"));
242 assert!(output.contains("func.func"));
243 }
244 #[test]
245 pub(super) fn test_backend_run_passes_empty() {
246 let backend = MlirBackend::new();
247 assert_eq!(backend.run_passes(), "");
248 }
249 #[test]
250 pub(super) fn test_backend_run_passes_nonempty() {
251 let mut backend = MlirBackend::new();
252 backend.add_pass("convert-arith-to-llvm");
253 backend.add_pass("convert-func-to-llvm");
254 let passes = backend.run_passes();
255 assert!(passes.contains("mlir-opt"));
256 assert!(passes.contains("convert-arith-to-llvm"));
257 }
258 #[test]
259 pub(super) fn test_mlir_global_emit() {
260 let global = MlirGlobal::constant("pi", MlirType::Float(64), MlirAttr::Float(3.14159));
261 let output = global.emit();
262 assert!(output.contains("@pi"));
263 assert!(output.contains("constant"));
264 }
265 #[test]
266 pub(super) fn test_ssa_counter_sequential() {
267 let mut counter = SsaCounter::new();
268 let v0 = counter.next(MlirType::Integer(64, false));
269 let v1 = counter.next(MlirType::Integer(64, false));
270 assert_eq!(v0.name, "0");
271 assert_eq!(v1.name, "1");
272 }
273 #[test]
274 pub(super) fn test_ssa_counter_reset() {
275 let mut counter = SsaCounter::new();
276 let _ = counter.next(MlirType::Integer(32, false));
277 counter.reset();
278 let v = counter.next(MlirType::Integer(32, false));
279 assert_eq!(v.name, "0");
280 }
281 #[test]
282 pub(super) fn test_dialect_display() {
283 assert_eq!(MlirDialect::Arith.to_string(), "arith");
284 assert_eq!(MlirDialect::Func.to_string(), "func");
285 assert_eq!(MlirDialect::SCF.to_string(), "scf");
286 assert_eq!(MlirDialect::GPU.to_string(), "gpu");
287 assert_eq!(MlirDialect::Linalg.to_string(), "linalg");
288 }
289 #[test]
290 pub(super) fn test_cmpi_pred_display() {
291 assert_eq!(CmpiPred::Eq.to_string(), "eq");
292 assert_eq!(CmpiPred::Slt.to_string(), "slt");
293 assert_eq!(CmpiPred::Uge.to_string(), "uge");
294 }
295 #[test]
296 pub(super) fn test_cmpf_pred_display() {
297 assert_eq!(CmpfPred::Oeq.to_string(), "oeq");
298 assert_eq!(CmpfPred::Une.to_string(), "une");
299 }
300 #[test]
301 pub(super) fn test_builder_extsi() {
302 let mut b = MlirBuilder::new();
303 let v = MlirValue::named("small", MlirType::Integer(32, false));
304 let result = b.extsi(v, 64);
305 assert!(matches!(result.ty, MlirType::Integer(64, false)));
306 let ops = b.take_ops();
307 assert_eq!(ops[0].op_name, "arith.extsi");
308 }
309 #[test]
310 pub(super) fn test_builder_trunci() {
311 let mut b = MlirBuilder::new();
312 let v = MlirValue::named("big", MlirType::Integer(64, false));
313 let result = b.trunci(v, 32);
314 assert!(matches!(result.ty, MlirType::Integer(32, false)));
315 let ops = b.take_ops();
316 assert_eq!(ops[0].op_name, "arith.trunci");
317 }
318 #[test]
319 pub(super) fn test_backend_compile_decl() {
320 let mut backend = MlirBackend::new();
321 backend.compile_decl(
322 "my_func",
323 vec![MlirType::Integer(64, false)],
324 MlirType::Integer(64, false),
325 );
326 let output = backend.emit_module();
327 assert!(output.contains("my_func"));
328 }
329 #[test]
330 pub(super) fn test_affine_map_identity() {
331 let am = AffineMap::Identity(2);
332 let s = am.to_string();
333 assert!(s.contains("affine_map"));
334 assert!(s.contains("d0"));
335 assert!(s.contains("d1"));
336 }
337 #[test]
338 pub(super) fn test_mlir_block_labeled() {
339 let block = MlirBlock::labeled("bb1", vec![], vec![]);
340 let s = format!("{}", block);
341 assert!(s.contains("^bb1"));
342 }
343 #[test]
344 pub(super) fn test_mlir_func_declaration() {
345 let decl = MlirFunc::declaration(
346 "extern_func",
347 vec![MlirType::Integer(32, false)],
348 vec![MlirType::Integer(32, false)],
349 );
350 let output = decl.emit();
351 assert!(output.contains("extern_func"));
352 assert!(output.contains("private"));
353 }
354 #[test]
355 pub(super) fn test_builder_math_ops() {
356 let mut b = MlirBuilder::new();
357 let v = MlirValue::named("x", MlirType::Float(32));
358 let _ = b.cos(v.clone());
359 let _ = b.exp(v.clone());
360 let _ = b.log(v.clone());
361 let _ = b.sqrt(v);
362 let ops = b.take_ops();
363 assert_eq!(ops[0].op_name, "math.cos");
364 assert_eq!(ops[1].op_name, "math.exp");
365 assert_eq!(ops[2].op_name, "math.log");
366 assert_eq!(ops[3].op_name, "math.sqrt");
367 }
368 #[test]
369 pub(super) fn test_unranked_memref() {
370 let ty = MlirType::UnrankedMemRef(Box::new(MlirType::Float(32)));
371 assert_eq!(ty.to_string(), "memref<*xf32>");
372 }
373 #[test]
374 pub(super) fn test_complex_type() {
375 let ty = MlirType::Complex(Box::new(MlirType::Float(32)));
376 assert_eq!(ty.to_string(), "complex<f32>");
377 }
378}
379#[cfg(test)]
380mod MLIR_infra_tests {
381 use super::*;
382 #[test]
383 pub(super) fn test_pass_config() {
384 let config = MLIRPassConfig::new("test_pass", MLIRPassPhase::Transformation);
385 assert!(config.enabled);
386 assert!(config.phase.is_modifying());
387 assert_eq!(config.phase.name(), "transformation");
388 }
389 #[test]
390 pub(super) fn test_pass_stats() {
391 let mut stats = MLIRPassStats::new();
392 stats.record_run(10, 100, 3);
393 stats.record_run(20, 200, 5);
394 assert_eq!(stats.total_runs, 2);
395 assert!((stats.average_changes_per_run() - 15.0).abs() < 0.01);
396 assert!((stats.success_rate() - 1.0).abs() < 0.01);
397 let s = stats.format_summary();
398 assert!(s.contains("Runs: 2/2"));
399 }
400 #[test]
401 pub(super) fn test_pass_registry() {
402 let mut reg = MLIRPassRegistry::new();
403 reg.register(MLIRPassConfig::new("pass_a", MLIRPassPhase::Analysis));
404 reg.register(MLIRPassConfig::new("pass_b", MLIRPassPhase::Transformation).disabled());
405 assert_eq!(reg.total_passes(), 2);
406 assert_eq!(reg.enabled_count(), 1);
407 reg.update_stats("pass_a", 5, 50, 2);
408 let stats = reg.get_stats("pass_a").expect("stats should exist");
409 assert_eq!(stats.total_changes, 5);
410 }
411 #[test]
412 pub(super) fn test_analysis_cache() {
413 let mut cache = MLIRAnalysisCache::new(10);
414 cache.insert("key1".to_string(), vec![1, 2, 3]);
415 assert!(cache.get("key1").is_some());
416 assert!(cache.get("key2").is_none());
417 assert!((cache.hit_rate() - 0.5).abs() < 0.01);
418 cache.invalidate("key1");
419 assert!(!cache.entries["key1"].valid);
420 assert_eq!(cache.size(), 1);
421 }
422 #[test]
423 pub(super) fn test_worklist() {
424 let mut wl = MLIRWorklist::new();
425 assert!(wl.push(1));
426 assert!(wl.push(2));
427 assert!(!wl.push(1));
428 assert_eq!(wl.len(), 2);
429 assert_eq!(wl.pop(), Some(1));
430 assert!(!wl.contains(1));
431 assert!(wl.contains(2));
432 }
433 #[test]
434 pub(super) fn test_dominator_tree() {
435 let mut dt = MLIRDominatorTree::new(5);
436 dt.set_idom(1, 0);
437 dt.set_idom(2, 0);
438 dt.set_idom(3, 1);
439 assert!(dt.dominates(0, 3));
440 assert!(dt.dominates(1, 3));
441 assert!(!dt.dominates(2, 3));
442 assert!(dt.dominates(3, 3));
443 }
444 #[test]
445 pub(super) fn test_liveness() {
446 let mut liveness = MLIRLivenessInfo::new(3);
447 liveness.add_def(0, 1);
448 liveness.add_use(1, 1);
449 assert!(liveness.defs[0].contains(&1));
450 assert!(liveness.uses[1].contains(&1));
451 }
452 #[test]
453 pub(super) fn test_constant_folding() {
454 assert_eq!(MLIRConstantFoldingHelper::fold_add_i64(3, 4), Some(7));
455 assert_eq!(MLIRConstantFoldingHelper::fold_div_i64(10, 0), None);
456 assert_eq!(MLIRConstantFoldingHelper::fold_div_i64(10, 2), Some(5));
457 assert_eq!(
458 MLIRConstantFoldingHelper::fold_bitand_i64(0b1100, 0b1010),
459 0b1000
460 );
461 assert_eq!(MLIRConstantFoldingHelper::fold_bitnot_i64(0), -1);
462 }
463 #[test]
464 pub(super) fn test_dep_graph() {
465 let mut g = MLIRDepGraph::new();
466 g.add_dep(1, 2);
467 g.add_dep(2, 3);
468 g.add_dep(1, 3);
469 assert_eq!(g.dependencies_of(2), vec![1]);
470 let topo = g.topological_sort();
471 assert_eq!(topo.len(), 3);
472 assert!(!g.has_cycle());
473 let pos: std::collections::HashMap<u32, usize> =
474 topo.iter().enumerate().map(|(i, &n)| (n, i)).collect();
475 assert!(pos[&1] < pos[&2]);
476 assert!(pos[&1] < pos[&3]);
477 assert!(pos[&2] < pos[&3]);
478 }
479}
480#[cfg(test)]
481mod mlirext_pass_tests {
482 use super::*;
483 #[test]
484 pub(super) fn test_mlirext_phase_order() {
485 assert_eq!(MLIRExtPassPhase::Early.order(), 0);
486 assert_eq!(MLIRExtPassPhase::Middle.order(), 1);
487 assert_eq!(MLIRExtPassPhase::Late.order(), 2);
488 assert_eq!(MLIRExtPassPhase::Finalize.order(), 3);
489 assert!(MLIRExtPassPhase::Early.is_early());
490 assert!(!MLIRExtPassPhase::Early.is_late());
491 }
492 #[test]
493 pub(super) fn test_mlirext_config_builder() {
494 let c = MLIRExtPassConfig::new("p")
495 .with_phase(MLIRExtPassPhase::Late)
496 .with_max_iter(50)
497 .with_debug(1);
498 assert_eq!(c.name, "p");
499 assert_eq!(c.max_iterations, 50);
500 assert!(c.is_debug_enabled());
501 assert!(c.enabled);
502 let c2 = c.disabled();
503 assert!(!c2.enabled);
504 }
505 #[test]
506 pub(super) fn test_mlirext_stats() {
507 let mut s = MLIRExtPassStats::new();
508 s.visit();
509 s.visit();
510 s.modify();
511 s.iterate();
512 assert_eq!(s.nodes_visited, 2);
513 assert_eq!(s.nodes_modified, 1);
514 assert!(s.changed);
515 assert_eq!(s.iterations, 1);
516 let e = s.efficiency();
517 assert!((e - 0.5).abs() < 1e-9);
518 }
519 #[test]
520 pub(super) fn test_mlirext_registry() {
521 let mut r = MLIRExtPassRegistry::new();
522 r.register(MLIRExtPassConfig::new("a").with_phase(MLIRExtPassPhase::Early));
523 r.register(MLIRExtPassConfig::new("b").disabled());
524 assert_eq!(r.len(), 2);
525 assert_eq!(r.enabled_passes().len(), 1);
526 assert_eq!(r.passes_in_phase(&MLIRExtPassPhase::Early).len(), 1);
527 }
528 #[test]
529 pub(super) fn test_mlirext_cache() {
530 let mut c = MLIRExtCache::new(4);
531 assert!(c.get(99).is_none());
532 c.put(99, vec![1, 2, 3]);
533 let v = c.get(99).expect("v should be present in map");
534 assert_eq!(v, &[1u8, 2, 3]);
535 assert!(c.hit_rate() > 0.0);
536 assert_eq!(c.live_count(), 1);
537 }
538 #[test]
539 pub(super) fn test_mlirext_worklist() {
540 let mut w = MLIRExtWorklist::new(10);
541 w.push(5);
542 w.push(3);
543 w.push(5);
544 assert_eq!(w.len(), 2);
545 assert!(w.contains(5));
546 let first = w.pop().expect("first should be available to pop");
547 assert!(!w.contains(first));
548 }
549 #[test]
550 pub(super) fn test_mlirext_dom_tree() {
551 let mut dt = MLIRExtDomTree::new(5);
552 dt.set_idom(1, 0);
553 dt.set_idom(2, 0);
554 dt.set_idom(3, 1);
555 dt.set_idom(4, 1);
556 assert!(dt.dominates(0, 3));
557 assert!(dt.dominates(1, 4));
558 assert!(!dt.dominates(2, 3));
559 assert_eq!(dt.depth_of(3), 2);
560 }
561 #[test]
562 pub(super) fn test_mlirext_liveness() {
563 let mut lv = MLIRExtLiveness::new(3);
564 lv.add_def(0, 1);
565 lv.add_use(1, 1);
566 assert!(lv.var_is_def_in_block(0, 1));
567 assert!(lv.var_is_used_in_block(1, 1));
568 assert!(!lv.var_is_def_in_block(1, 1));
569 }
570 #[test]
571 pub(super) fn test_mlirext_const_folder() {
572 let mut cf = MLIRExtConstFolder::new();
573 assert_eq!(cf.add_i64(3, 4), Some(7));
574 assert_eq!(cf.div_i64(10, 0), None);
575 assert_eq!(cf.mul_i64(6, 7), Some(42));
576 assert_eq!(cf.and_i64(0b1100, 0b1010), 0b1000);
577 assert_eq!(cf.fold_count(), 3);
578 assert_eq!(cf.failure_count(), 1);
579 }
580 #[test]
581 pub(super) fn test_mlirext_dep_graph() {
582 let mut g = MLIRExtDepGraph::new(4);
583 g.add_edge(0, 1);
584 g.add_edge(1, 2);
585 g.add_edge(2, 3);
586 assert!(!g.has_cycle());
587 assert_eq!(g.topo_sort(), Some(vec![0, 1, 2, 3]));
588 assert_eq!(g.reachable(0).len(), 4);
589 let sccs = g.scc();
590 assert_eq!(sccs.len(), 4);
591 }
592}