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}
19pub 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}