cairo_lang_lowering/graph_algorithms/
strongly_connected_components.rs1use std::cmp::Ordering;
2
3use cairo_lang_defs::stable_order::{cmp_elements, cmp_nodes};
4use cairo_lang_semantic::stable_order::{StableOrd, cmp_slices};
5use cairo_lang_syntax::node::TypedStablePtr;
6use cairo_lang_utils::graph_algos::strongly_connected_components::compute_scc;
7use salsa::Database;
8
9use super::concrete_function_node::ConcreteFunctionWithBodyNode;
10use crate::db::{ConcreteSCCRepresentative, LoweringGroup};
11use crate::ids::{
12 ConcreteFunctionWithBodyId, ConcreteFunctionWithBodyLongId, GeneratedFunctionKey,
13};
14use crate::specialization::SpecializationArg;
15use crate::{DependencyType, LoweringStage};
16
17#[salsa::tracked(returns(clone))]
20pub fn lowered_scc_representative<'db>(
21 db: &'db dyn Database,
22 function: ConcreteFunctionWithBodyId<'db>,
23 dependency_type: DependencyType,
24 stage: LoweringStage,
25) -> ConcreteSCCRepresentative<'db> {
26 ConcreteSCCRepresentative(
27 db.lowered_scc(function, dependency_type, stage)
28 .into_iter()
29 .min_by(|a, b| a.stable_cmp(b, db))
30 .unwrap_or(function),
31 )
32}
33
34#[salsa::tracked(returns(clone))]
36pub fn lowered_scc<'db>(
37 db: &'db dyn Database,
38 function_id: ConcreteFunctionWithBodyId<'db>,
39 dependency_type: DependencyType,
40 stage: LoweringStage,
41) -> Vec<ConcreteFunctionWithBodyId<'db>> {
42 compute_scc(&ConcreteFunctionWithBodyNode { function_id, db, dependency_type, stage })
43}
44
45impl<'db> StableOrd<'db> for ConcreteFunctionWithBodyId<'db> {
48 fn stable_cmp(&self, other: &Self, db: &'db dyn Database) -> Ordering {
49 use ConcreteFunctionWithBodyLongId::*;
50 let kind = |function: &ConcreteFunctionWithBodyLongId<'db>| match function {
51 Semantic(_) => 0,
52 Generated(_) => 1,
53 Specialized(_) => 2,
54 };
55 let (a, b) = (self.long(db), other.long(db));
56 a.base_semantic_function(db)
57 .stable_cmp(&b.base_semantic_function(db), db)
58 .then_with(|| kind(a).cmp(&kind(b)))
59 .then_with(|| match (a, b) {
60 (Generated(a), Generated(b)) => a.key.stable_cmp(&b.key, db),
61 (Specialized(a), Specialized(b)) => {
62 let (a, b) = (a.long(db), b.long(db));
63 a.base.stable_cmp(&b.base, db).then_with(|| cmp_slices(db, &a.args, &b.args))
64 }
65 _ => Ordering::Equal,
66 })
67 }
68}
69
70impl<'db> StableOrd<'db> for GeneratedFunctionKey<'db> {
72 fn stable_cmp(&self, other: &Self, db: &'db dyn Database) -> Ordering {
73 use GeneratedFunctionKey::*;
74 match (self, other) {
75 (Loop(a), Loop(b)) => cmp_nodes(db, a.untyped(), b.untyped()),
76 (TraitFunc(a_function, a), TraitFunc(b_function, b)) => {
77 cmp_nodes(db, a.stable_ptr(), b.stable_ptr())
78 .then_with(|| cmp_elements(db, a_function, b_function))
79 }
80 (Loop(_), TraitFunc(..)) => Ordering::Less,
81 (TraitFunc(..), Loop(_)) => Ordering::Greater,
82 }
83 }
84}
85
86impl<'db> StableOrd<'db> for SpecializationArg<'db> {
88 fn stable_cmp(&self, other: &Self, db: &'db dyn Database) -> Ordering {
89 use SpecializationArg::*;
90 let kind = |arg: &Self| match arg {
91 Const { .. } => 0,
92 Snapshot(_) => 1,
93 Array(..) => 2,
94 Struct(_) => 3,
95 Enum { .. } => 4,
96 NotSpecialized => 5,
97 };
98 match (self, other) {
99 (Const { value: a, boxed: a_boxed }, Const { value: b, boxed: b_boxed }) => {
100 a.stable_cmp(b, db).then_with(|| a_boxed.cmp(b_boxed))
101 }
102 (Snapshot(a), Snapshot(b)) => a.stable_cmp(b, db),
103 (Array(a_ty, a), Array(b_ty, b)) => {
104 a_ty.stable_cmp(b_ty, db).then_with(|| cmp_slices(db, a, b))
105 }
106 (Struct(a), Struct(b)) => cmp_slices(db, a, b),
107 (Enum { variant: a, payload: a_payload }, Enum { variant: b, payload: b_payload }) => {
108 a.stable_cmp(b, db).then_with(|| a_payload.stable_cmp(b_payload, db))
109 }
110 (NotSpecialized, NotSpecialized) => Ordering::Equal,
111 (a, b) => kind(a).cmp(&kind(b)),
112 }
113 }
114}