pit_patch/
tutils.rs

1use core::iter::once;
2use alloc::{boxed::Box, vec};
3use alloc::vec::Vec;
4
5use portal_pc_waffle::op_traits::op_outputs;
6use portal_pc_waffle::{SignatureData, Type};
7use portal_pc_waffle::{util::new_sig, Block, BlockTarget, Func, FunctionBody, Module, Operator, Table, Value};
8
9use crate::util::add_op;
10pub trait Builder {
11    type Result;
12    fn build(
13        &mut self,
14        mo: &mut Module,
15        func: &mut FunctionBody,
16        k: Block,
17    ) -> anyhow::Result<(Self::Result, Block)>;
18}
19// use crate::*;
20pub enum Expr {
21    Leaf(Value),
22    Bind(Operator, Vec<Expr>),
23    Mount(Box<dyn Builder<Result = portal_pc_waffle::Value>>),
24}
25impl Builder for Expr {
26    type Result = portal_pc_waffle::Value;
27
28    fn build(
29        &mut self,
30        mo: &mut portal_pc_waffle::Module,
31        func: &mut portal_pc_waffle::FunctionBody,
32        mut k: portal_pc_waffle::Block,
33    ) -> anyhow::Result<(Self::Result, portal_pc_waffle::Block)> {
34        match self {
35            Expr::Leaf(a) => Ok((*a, k)),
36            Expr::Bind(a, c) => {
37                let mut r = vec![];
38                for d in c.iter_mut() {
39                    let (e, f) = d.build(mo, func, k)?;
40                    k = f;
41                    r.push(e);
42                }
43                let o = add_op(func, &r, &op_outputs(&mo, None, &a)?, a.clone());
44                func.append_to_block(k, o);
45                return Ok((o, k));
46            }
47            Expr::Mount(m) => m.build(mo, func, k),
48        }
49    }
50}
51pub fn talloc(m: &mut Module, t: Table, aux: &[Table]) -> anyhow::Result<Func> {
52    let e = m.tables[t].ty.clone();
53    let atys = aux
54        .iter()
55        .map(|a| m.tables[*a].ty.clone())
56        .collect::<Vec<_>>();
57    let sig = new_sig(
58        m,
59        SignatureData::Func {
60            params: vec![e].into_iter().chain(atys.into_iter()).collect(),
61            returns: vec![Type::I32],
62            shared: true,
63        },
64    );
65    let mut f = FunctionBody::new(m, sig);
66    let avals = f.blocks[f.entry].params[1..]
67        .iter()
68        .map(|a| a.1)
69        .collect::<Vec<_>>();
70    let n = f.add_block();
71    let zero = add_op(&mut f, &[], &[Type::I32], Operator::I32Const { value: 0 });
72    f.append_to_block(f.entry, zero);
73    f.set_terminator(
74        f.entry,
75        portal_pc_waffle::Terminator::Br {
76            target: BlockTarget {
77                block: n,
78                args: vec![zero],
79            },
80        },
81    );
82    let idx = f.add_blockparam(n, Type::I32);
83    let mut e = Expr::Bind(
84        Operator::RefIsNull,
85        vec![Expr::Bind(
86            Operator::TableGet { table_index: t },
87            vec![Expr::Leaf(idx)],
88        )],
89    );
90    let (r, o) = e.build(m, &mut f, n)?;
91    let mut e = Expr::Bind(
92        Operator::I32Add,
93        vec![
94            Expr::Bind(Operator::I32Const { value: 1 }, vec![]),
95            Expr::Leaf(idx),
96        ],
97    );
98    let (s, o) = e.build(m, &mut f, o)?;
99    let p = f.add_block();
100    f.set_terminator(
101        o,
102        portal_pc_waffle::Terminator::CondBr {
103            cond: r,
104            if_true: BlockTarget {
105                block: p,
106                args: vec![],
107            },
108            if_false: BlockTarget {
109                block: n,
110                args: vec![s],
111            },
112        },
113    );
114    let q = f.add_block();
115    let r = f.add_block();
116    let mut e = Expr::Bind(
117        Operator::I32Eq,
118        vec![
119            Expr::Bind(Operator::TableSize { table_index: t }, vec![]),
120            Expr::Leaf(idx),
121        ],
122    );
123    let (s, o) = e.build(m, &mut f, p)?;
124    f.set_terminator(
125        o,
126        portal_pc_waffle::Terminator::CondBr {
127            cond: s,
128            if_true: BlockTarget {
129                block: r,
130                args: vec![],
131            },
132            if_false: BlockTarget {
133                block: q,
134                args: vec![],
135            },
136        },
137    );
138    let mut e = Expr::Bind(
139        Operator::TableSet { table_index: t },
140        vec![Expr::Leaf(idx), Expr::Leaf(f.blocks[f.entry].params[0].1)],
141    );
142    let (s, mut o) = e.build(m, &mut f, q)?;
143    for (a, v) in aux.iter().zip(avals.iter()) {
144        let b = f.add_block();
145        let d = f.add_block();
146        let mut e = Expr::Bind(
147            Operator::I32GeU,
148            vec![
149                Expr::Leaf(idx),
150                Expr::Bind(Operator::TableSize { table_index: *a }, vec![]),
151            ],
152        );
153        let c;
154        (c, o) = e.build(m, &mut f, o)?;
155        f.set_terminator(
156            o,
157            portal_pc_waffle::Terminator::CondBr {
158                cond: c,
159                if_true: BlockTarget {
160                    block: b,
161                    args: vec![],
162                },
163                if_false: BlockTarget {
164                    block: d,
165                    args: vec![],
166                },
167            },
168        );
169        let mut e = Expr::Bind(
170            Operator::TableGrow { table_index: *a },
171            vec![Expr::Bind(
172                Operator::I32Sub,
173                vec![
174                    Expr::Leaf(idx),
175                    Expr::Bind(Operator::TableSize { table_index: *a }, vec![]),
176                ],
177            )],
178        );
179        let (_, b) = e.build(m, &mut f, b)?;
180        f.set_terminator(
181            b,
182            portal_pc_waffle::Terminator::Br {
183                target: BlockTarget {
184                    block: d,
185                    args: vec![],
186                },
187            },
188        );
189        o = d;
190        f.add_op(o, Operator::TableSet { table_index: *a }, &[idx, *v], &[]);
191    }
192    f.set_terminator(o, portal_pc_waffle::Terminator::Return { values: vec![idx] });
193    let mut e = Expr::Bind(
194        Operator::TableGrow { table_index: t },
195        vec![
196            Expr::Bind(Operator::I32Const { value: 1 }, vec![]),
197            Expr::Leaf(f.blocks[f.entry].params[0].1),
198        ],
199    );
200    let (s, mut o) = e.build(m, &mut f, r)?;
201    for (a, v) in aux.iter().zip(avals.iter()) {
202        let b = f.add_block();
203        let d = f.add_block();
204        let mut e = Expr::Bind(
205            Operator::I32GeU,
206            vec![
207                Expr::Leaf(idx),
208                Expr::Bind(Operator::TableSize { table_index: *a }, vec![]),
209            ],
210        );
211        let c;
212        (c, o) = e.build(m, &mut f, o)?;
213        f.set_terminator(
214            o,
215            portal_pc_waffle::Terminator::CondBr {
216                cond: c,
217                if_true: BlockTarget {
218                    block: b,
219                    args: vec![],
220                },
221                if_false: BlockTarget {
222                    block: d,
223                    args: vec![],
224                },
225            },
226        );
227        let mut e = Expr::Bind(
228            Operator::TableGrow { table_index: *a },
229            vec![Expr::Bind(
230                Operator::I32Sub,
231                vec![
232                    Expr::Leaf(idx),
233                    Expr::Bind(Operator::TableSize { table_index: *a }, vec![]),
234                ],
235            )],
236        );
237        let (_, b) = e.build(m, &mut f, b)?;
238        f.set_terminator(
239            b,
240            portal_pc_waffle::Terminator::Br {
241                target: BlockTarget {
242                    block: d,
243                    args: vec![],
244                },
245            },
246        );
247        o = d;
248        f.add_op(o, Operator::TableSet { table_index: *a }, &[idx, *v], &[]);
249    }
250    f.set_terminator(o, portal_pc_waffle::Terminator::Return { values: vec![idx] });
251    return Ok(m
252        .funcs
253        .push(portal_pc_waffle::FuncDecl::Body(sig, alloc::format!("talloc"), f)));
254}
255pub fn tfree(m: &mut Module, t: Table, aux: &[Table]) -> anyhow::Result<Func> {
256    let ety = m.tables[t].ty.clone();
257    let atys = aux
258        .iter()
259        .map(|a| m.tables[*a].ty.clone())
260        .collect::<Vec<_>>();
261    let sig = new_sig(
262        m,
263        SignatureData::Func {
264            params: vec![Type::I32],
265            returns: vec![ety.clone()]
266                .into_iter()
267                .chain(atys.into_iter())
268                .collect(),
269                shared: true,
270        },
271    );
272    let mut f = FunctionBody::new(m, sig);
273    let o = f.entry;
274    let e = f.blocks[f.entry].params[0].1;
275    let r = once(t)
276        .chain(aux.iter().cloned())
277        .zip(f.rets.clone().into_iter())
278        .map(|(t, e2)| f.add_op(o, Operator::TableGet { table_index: t }, &[e], &[e2]))
279        .collect();
280    let mut e = Expr::Bind(
281        Operator::TableSet { table_index: t },
282        vec![
283            Expr::Leaf(f.blocks[f.entry].params[0].1),
284            Expr::Bind(Operator::RefNull { ty: ety }, vec![]),
285        ],
286    );
287    let (_, o) = e.build(m, &mut f, o)?;
288    f.set_terminator(o, portal_pc_waffle::Terminator::Return { values: r });
289    return Ok(m
290        .funcs
291        .push(portal_pc_waffle::FuncDecl::Body(sig, alloc::format!("tfree"), f)));
292}