1use serde_derive::{Deserialize, Serialize};
2
3use crate::{impl_op, Graph, Ref, Type};
4
5use super::{unique_for, Op};
6
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9pub struct Add;
10
11#[typetag::serde]
12impl Op for Add {
13 impl_op! {}
14
15 fn annotate(&mut self, self_id: usize, graph: &Graph, args: &[Type]) -> Option<Type> {
16 Some(match args {
17 [Type::Float, Type::Float] => Type::Float,
18 _ => return None,
19 })
20 }
21
22 fn render_into(
23 &self,
24 graph: &Graph,
25 output: qbe::Value,
26 args: &[Ref],
27 func: &mut qbe::Function,
28 namespace: &str,
29 ) {
30 func.assign_instr(
31 output,
32 Type::Float.render(),
33 qbe::Instr::Add(args[0].render(), args[1].render()),
34 )
35 }
36
37 fn const_eval(&self, graph: &Graph, args: &[Ref]) -> Option<Ref> {
38 if Ref::from(0.0) == args[0] {
39 return Some(args[1]);
40 }
41
42 if Ref::from(0.0) == args[1] {
43 return Some(args[0]);
44 }
45
46 if let Some((x, y)) = args[0].as_f64().zip(args[1].as_f64()) {
47 return Some((x + y).into());
48 }
49
50 None
51 }
52}
53
54#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
56pub struct Sub;
57
58#[typetag::serde]
59impl Op for Sub {
60 impl_op! {}
61
62 fn annotate(&mut self, self_id: usize, graph: &Graph, args: &[Type]) -> Option<Type> {
63 Some(match args {
64 [Type::Float, Type::Float] => Type::Float,
65 _ => return None,
66 })
67 }
68
69 fn render_into(
70 &self,
71 graph: &Graph,
72 output: qbe::Value,
73 args: &[Ref],
74 func: &mut qbe::Function,
75 namespace: &str,
76 ) {
77 func.assign_instr(
78 output,
79 Type::Float.render(),
80 qbe::Instr::Sub(args[0].render(), args[1].render()),
81 )
82 }
83
84 fn const_eval(&self, graph: &Graph, args: &[Ref]) -> Option<Ref> {
85 if let Ref::Const(Type::Float, 0) = args[1] {
86 return Some(args[0]);
87 }
88
89 if let Some((x, y)) = args[0].as_f64().zip(args[1].as_f64()) {
90 return Some((x - y).into());
91 }
92
93 None
94 }
95}
96
97#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
99pub struct Mul;
100
101#[typetag::serde]
102impl Op for Mul {
103 impl_op! {}
104
105 fn annotate(&mut self, self_id: usize, graph: &Graph, args: &[Type]) -> Option<Type> {
106 Some(match args {
107 [Type::Float, Type::Float] => Type::Float,
108 _ => return None,
109 })
110 }
111
112 fn render_into(
113 &self,
114 graph: &Graph,
115 output: qbe::Value,
116 args: &[Ref],
117 func: &mut qbe::Function,
118 namespace: &str,
119 ) {
120 func.assign_instr(
121 output,
122 Type::Float.render(),
123 qbe::Instr::Mul(args[0].render(), args[1].render()),
124 )
125 }
126
127 fn const_eval(&self, graph: &Graph, args: &[Ref]) -> Option<Ref> {
128 if Ref::from(1.0) == args[0] {
129 return Some(args[1]);
130 }
131
132 if Ref::from(1.0) == args[1] {
133 return Some(args[0]);
134 }
135
136 if let Some((x, y)) = args[0].as_f64().zip(args[1].as_f64()) {
137 return Some((x * y).into());
138 }
139
140 None
141 }
142}
143
144#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
146pub struct Div;
147
148#[typetag::serde]
149impl Op for Div {
150 impl_op! {}
151
152 fn annotate(&mut self, self_id: usize, graph: &Graph, args: &[Type]) -> Option<Type> {
153 Some(match args {
154 [Type::Float, Type::Float] => Type::Float,
155 _ => return None,
156 })
157 }
158
159 fn render_into(
160 &self,
161 graph: &Graph,
162 output: qbe::Value,
163 args: &[Ref],
164 func: &mut qbe::Function,
165 namespace: &str,
166 ) {
167 func.assign_instr(
168 output,
169 Type::Float.render(),
170 qbe::Instr::Div(args[0].render(), args[1].render()),
171 )
172 }
173
174 fn const_eval(&self, graph: &Graph, args: &[Ref]) -> Option<Ref> {
175 if Ref::from(1.0) == args[1] {
176 return Some(args[0]);
177 }
178
179 if let Some((x, y)) = args[0].as_f64().zip(args[1].as_f64()) {
180 return Some((x / y).into());
181 }
182
183 None
184 }
185}
186
187#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
189pub struct Rem;
190
191#[typetag::serde]
192impl Op for Rem {
193 impl_op! {}
194
195 fn annotate(&mut self, self_id: usize, graph: &Graph, args: &[Type]) -> Option<Type> {
196 Some(match args {
197 [Type::Float, Type::Float] => Type::Float,
198 _ => return None,
199 })
200 }
201
202 fn render_into(
203 &self,
204 graph: &Graph,
205 output: qbe::Value,
206 args: &[Ref],
207 func: &mut qbe::Function,
208 namespace: &str,
209 ) {
210 super::call::Call("rem".to_string()).render_into(graph, output, args, func, namespace)
212 }
213
214 fn const_eval(&self, graph: &Graph, args: &[Ref]) -> Option<Ref> {
215 if let Some((x, y)) = args[0].as_f64().zip(args[1].as_f64()) {
216 return Some((x % y).into());
217 }
218
219 None
220 }
221}
222
223#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
225pub struct Neg;
226
227#[typetag::serde]
228impl Op for Neg {
229 impl_op! {}
230
231 fn annotate(&mut self, self_id: usize, graph: &Graph, args: &[Type]) -> Option<Type> {
232 Some(match args {
233 [Type::Float] => Type::Float,
234 _ => return None,
235 })
236 }
237
238 fn render_into(
239 &self,
240 graph: &Graph,
241 output: qbe::Value,
242 args: &[Ref],
243 func: &mut qbe::Function,
244 namespace: &str,
245 ) {
246 func.assign_instr(
247 output,
248 Type::Float.render(),
249 qbe::Instr::Neg(args[0].render()),
250 )
251 }
252
253 fn const_eval(&self, graph: &Graph, args: &[Ref]) -> Option<Ref> {
254 if let Some(x) = args[0].as_f64() {
255 return Some((-x).into());
256 }
257
258 None
259 }
260}
261
262#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
264pub struct Abs;
265
266#[typetag::serde]
267impl Op for Abs {
268 impl_op! {}
269
270 fn annotate(&mut self, self_id: usize, graph: &Graph, args: &[Type]) -> Option<Type> {
271 Some(match args {
272 [Type::Float] => Type::Float,
273 _ => return None,
274 })
275 }
276
277 fn render_into(
278 &self,
279 graph: &Graph,
280 output: qbe::Value,
281 args: &[Ref],
282 func: &mut qbe::Function,
283 namespace: &str,
284 ) {
285 let test_temp = qbe::Value::Temporary(unique_for(output.clone(), "abs.test"));
286 func.assign_instr(
287 test_temp.clone(),
288 qbe::Type::Byte,
289 qbe::Instr::Cmp(
290 Type::Float.render(),
291 qbe::Cmp::Ge,
292 args[0].render(),
293 qbe::Value::Const(0),
294 ),
295 );
296
297 let true_side = unique_for(output.clone(), "abs.if.true");
298 let false_side = unique_for(output.clone(), "abs.if.false");
299 let end_side = unique_for(output.clone(), "abs.if.end");
300
301 func.add_instr(qbe::Instr::Jnz(
302 test_temp,
303 true_side.clone(),
304 false_side.clone(),
305 ));
306
307 func.add_block(true_side);
308 func.assign_instr(
309 output.clone(),
310 Type::Float.render(),
311 qbe::Instr::Copy(args[0].render()),
312 );
313 func.add_instr(qbe::Instr::Jmp(end_side.clone()));
314
315 func.add_block(false_side);
316 func.assign_instr(
317 output,
318 Type::Float.render(),
319 qbe::Instr::Neg(args[0].render()),
320 );
321
322 func.add_block(end_side);
323 }
324
325 fn const_eval(&self, graph: &Graph, args: &[Ref]) -> Option<Ref> {
326 if let Some(x) = args[0].as_f64() {
327 return Some(x.abs().into());
328 }
329
330 None
331 }
332}