ssa_rust/
lib.rs

1use std::iter::empty;
2
3use arena_traits::{Arena, IndexIter};
4use cfg_traits::{Block as CFGBlock, Target as CFGTarget, Term as CFGTerm};
5use either::Either;
6use lending_iterator::prelude::*;
7use proc_macro2::{Span, TokenStream};
8use quasiquote::quasiquote;
9use quote::{format_ident, quote};
10use relooper::{BranchMode, RelooperLabel, ShapedBlock};
11use ssa_traits::{Block, Target, Term, TypedBlock, TypedFunc, TypedValue};
12use syn::{Ident, Lifetime};
13fn term(b: &BranchMode) -> TokenStream {
14    match b {
15        relooper::BranchMode::LoopBreak(l) => {
16            let l = Lifetime::new(&format!("'l{}", l), Span::call_site());
17            quote! {
18                break #l;
19            }
20        }
21        relooper::BranchMode::LoopBreakIntoMulti(l) => {
22            let l = Lifetime::new(&format!("'l{}", l), Span::call_site());
23            quote! {
24                break #l;
25            }
26        }
27        relooper::BranchMode::LoopContinue(l) => {
28            let l = Lifetime::new(&format!("'l{}", l), Span::call_site());
29            quote! {
30                continue #l;
31            }
32        }
33        relooper::BranchMode::LoopContinueIntoMulti(l) => {
34            let l = Lifetime::new(&format!("'l{}", l), Span::call_site());
35            quote! {
36                continue #l;
37            }
38        }
39        relooper::BranchMode::MergedBranch => {
40            quote! {}
41        }
42        relooper::BranchMode::MergedBranchIntoMulti => quote! {},
43        relooper::BranchMode::SetLabelAndBreak => quote! {
44            break 'cff;
45        },
46    }
47}
48pub trait RsFunc:
49    TypedFunc<
50        Ty: Rs<Self>,
51        Block: RsId<Self> + Ord + Clone + RelooperLabel,
52        Value: RsId<Self> + Clone,
53        Values: Arena<Self::Value, Output: Rs<Self>>,
54        Blocks: Arena<Self::Block, Output: Block<Self, Terminator: RsTerm<Self>>>,
55    > + Sized
56{
57}
58impl<
59        T: TypedFunc<
60                Ty: Rs<Self>,
61                Block: RsId<Self> + Ord + Clone + RelooperLabel,
62                Value: RsId<Self> + Clone,
63                Values: Arena<Self::Value, Output: Rs<Self>>,
64                Blocks: Arena<Self::Block, Output: Block<Self, Terminator: RsTerm<Self>>>,
65            > + Sized,
66    > RsFunc for T
67{
68}
69pub trait Rs<F: RsFunc> {
70    fn rs(&self, f: &F) -> anyhow::Result<TokenStream>;
71}
72pub trait RsId<F: RsFunc> {
73    fn rs(&self, f: &F) -> anyhow::Result<Ident>;
74}
75pub trait RsTerm<F: RsFunc> {
76    fn rs_term(
77        &self,
78        f: &F,
79        go: impl FnMut(F::Block) -> anyhow::Result<TokenStream>,
80    ) -> anyhow::Result<TokenStream>;
81}
82pub fn render_target<R: RsFunc>(
83    t: &impl Target<R>,
84    f: &R,
85    go: &mut impl FnMut(R::Block) -> anyhow::Result<TokenStream>,
86    prepend: impl Iterator<Item: Rs<R>>,
87) -> anyhow::Result<TokenStream> {
88    let vars = prepend
89        .map(|x| x.rs(f))
90        .chain(
91            t.values(f)
92                .map::<HKT!(<'b> => anyhow::Result<TokenStream>), _>(|[], a| {
93                    let a = format_ident!("V{}", a.rs(f)?);
94                    anyhow::Ok(quasiquote!(#a .take()))
95                })
96                .into_iter(),
97        )
98        .enumerate()
99        .map(|(i, a)| {
100            let i = format_ident!("P{}_{i}", t.block().rs(f)?);
101            Ok(quasiquote! {
102                #i = #{a?};
103            })
104        })
105        .collect::<anyhow::Result<Vec<_>>>()?;
106    Ok(quasiquote! {
107        #(#vars);*
108        #{go(t.block())?}
109    })
110}
111pub fn go<F: RsFunc>(params: &[TokenStream], f: &F, e: F::Block) -> anyhow::Result<TokenStream> {
112    Ok(quasiquote! {
113        #{
114            let k = f.blocks().iter().flat_map(|a|{
115                if a == e{
116                    Either::Left(params.iter().enumerate().map(move|(i,p)|Ok(quasiquote!(let mut #{format_ident!("P{}_{i}",a.rs(f)?)} = Some(#p)))))
117                }else{
118                    Either::Right(f.blocks()[a].params().map(|(a,_)|a).enumerate().map(move|(i,t)|Ok(quasiquote!(let mut #{format_ident!("P{}_{i}",a.rs(f)?)}: Option<#{t.rs(f)?}> = None))).collect::<Vec<_>>().into_iter())
119                }
120            }).chain(f.values().iter().map(|v|{
121                let ty = f.values()[v.clone()].ty(f).rs(f)?;
122                Ok(quote!{
123                    let mut #{format_ident!("V{}",v.rs(f)?)}: Option<#ty> = None;
124                })
125            })).collect::<anyhow::Result<Vec<_>>>()?;
126            quote! {
127                #(#k);*
128            }
129        };
130        let mut cff = 0usize;
131        #{block(f,ssa_reloop::go(f,e).as_ref())?}
132    })
133}
134pub fn idx_of<F: RsFunc>(f: &F, k: F::Block) -> usize {
135    f.blocks()
136        .iter()
137        .enumerate()
138        .find_map(|(i, l)| if l == k { Some(i) } else { None })
139        .unwrap()
140}
141pub fn block<F: RsFunc>(f: &F, k: &ShapedBlock<F::Block>) -> anyhow::Result<TokenStream> {
142    match k {
143        ShapedBlock::Loop(l) => {
144            let r = block(f, &l.inner.as_ref())?;
145            let next = l.next.as_ref();
146            let next = match next {
147                None => Default::default(),
148                Some(a) => block(f, a)?,
149            };
150            let l = Lifetime::new(&format!("'l{}", l.loop_id), Span::call_site());
151            Ok(quote! {
152                #l : loop{
153                    #r
154                };
155                #next;
156            })
157        }
158        ShapedBlock::Multiple(k) => {
159            let initial = k.handled.iter().enumerate().flat_map(|(a, b)| {
160                b.labels.iter().map(move |l| {
161                    let l = idx_of(f, *l);
162                    quote! {
163                        #l => #a
164                    }
165                })
166            });
167            let cases = k
168                .handled
169                .iter()
170                .enumerate()
171                .map(|(a, i)| {
172                    let ib = block(f, &i.inner)?;
173                    let ic = if i.break_after {
174                        quote! {}
175                    } else {
176                        quote! {
177                            cff2 += 1;
178                            continue 'cff
179                        }
180                    };
181                    Ok(quote! {
182                        #a => {
183                            #ib;
184                            #ic;
185                        }
186                    })
187                })
188                .collect::<anyhow::Result<Vec<_>>>()?;
189            Ok(quote! {
190                let mut cff2 = match cff{
191                    #(#initial),*,
192                    _ => unreachable!()
193                };
194                'cff: loop{
195                    match cff2{
196                        #(#cases),*,
197                        _ => unreachable!()
198                    };
199                    break 'cff;
200                };
201            })
202        }
203        ShapedBlock::Simple(s) => {
204            let immediate = match s.immediate.as_ref() {
205                None => Default::default(),
206                Some(a) => block(f, a)?,
207            };
208
209            let next = match s.next.as_ref() {
210                None => Default::default(),
211                Some(a) => block(f, a)?,
212            };
213            let stmts = f.blocks()[s.label]
214                .insts()
215                .map(|v| {
216                    Ok(quasiquote! {
217                        #{format_ident!("V{}",v.rs(f)?)} = Some(#{f.values()[v].rs(f)?})
218                    })
219                })
220                .collect::<anyhow::Result<Vec<_>>>()?;
221            let term = f.blocks()[s.label].term().rs_term(f, |k| {
222                let br = term(
223                    &s.branches
224                        .get(&k)
225                        .cloned()
226                        .unwrap_or(relooper::BranchMode::MergedBranch),
227                );
228                let bi = idx_of(f, k);
229                Ok(quote! {
230                    cff = #bi;
231                    #br
232                })
233            })?;
234            Ok(quote! {
235                #(#stmts);*;
236                #term;
237                #immediate;
238                #next;
239            })
240        }
241    }
242}
243#[cfg(feature = "id-arena")]
244impl<F: RsFunc, T> RsId<F> for id_arena::Id<T> {
245    fn rs(&self, f: &F) -> anyhow::Result<Ident> {
246        Ok(format_ident!("V{}", self.index()))
247    }
248}
249pub trait RsOp<F: RsFunc> {
250    fn rs_op(
251        &self,
252        f: &F,
253        all: &[impl RsId<F>],
254        blargs: &[F::Block],
255    ) -> anyhow::Result<TokenStream>;
256}
257#[cfg(feature = "ssa-canon")]
258impl<F: RsFunc<Block = id_arena::Id<ssa_canon::Block<O, T, Y>>>, O: RsOp<F>, T, Y> Rs<F>
259    for ssa_canon::Value<O, T, Y>
260{
261    fn rs(&self, f: &F) -> anyhow::Result<TokenStream> {
262        match self {
263            ssa_canon::Value::Op(o, args, q, _) => o.rs_op(f, &args, q.as_slice()),
264            ssa_canon::Value::Param(i, a, _) => {
265                Ok(quasiquote!(#{format_ident!("P{}_{i}",a.rs(f)?)}.take().unwrap()))
266            }
267        }
268    }
269}
270#[cfg(feature = "ssa-canon")]
271impl<
272        O: RsOp<ssa_canon::Func<O, T, Y>>,
273        T: Term<ssa_canon::Func<O, T, Y>, Target = ssa_canon::Target<O, T, Y>>,
274        Y: Clone,
275    > RsTerm<ssa_canon::Func<O, T, Y>> for ssa_canon::Target<O, T, Y>
276where
277    ssa_canon::Func<O, T, Y>: RsFunc<Block = id_arena::Id<ssa_canon::Block<O, T, Y>>>,
278{
279    fn rs_term(
280        &self,
281        f: &ssa_canon::Func<O, T, Y>,
282        mut go: impl FnMut(
283            <ssa_canon::Func<O, T, Y> as cfg_traits::Func>::Block,
284        ) -> anyhow::Result<TokenStream>,
285    ) -> anyhow::Result<TokenStream> {
286        render_target(self, f, &mut go, empty::<ssa_canon::Value<O, T, Y>>())
287    }
288}
289impl<F: RsFunc, A: RsOp<F>, B: RsOp<F>> RsOp<F> for Either<A, B> {
290    fn rs_op(
291        &self,
292        f: &F,
293        all: &[impl RsId<F>],
294        blargs: &[F::Block],
295    ) -> anyhow::Result<TokenStream> {
296        match self {
297            Either::Left(a) => a.rs_op(f, all, blargs),
298            Either::Right(b) => b.rs_op(f, all, blargs),
299        }
300    }
301}