ruda_kernel/dsl/frontend/operation/
base.rs1use ruda_core::ir::{
2 Arithmetic, BinaryOperator, Comparison, ElemType, IndexAssignOperator, IndexOperator,
3 Instruction, ManagedVariable, Operation, Operator, Scope, Type, UnaryOperator, Variable,
4 VariableKind, VectorSize,
5};
6use ruda_kernel_macros::ruda;
7
8use crate::dsl::{
9 prelude::{RudaIndex, RudaType, Int, NativeExpand, eq, rem},
10};
11
12pub(crate) fn binary_expand<F, Op>(
13 scope: &mut Scope,
14 lhs: ManagedVariable,
15 rhs: ManagedVariable,
16 func: F,
17) -> ManagedVariable
18where
19 F: Fn(BinaryOperator) -> Op,
20 Op: Into<Operation>,
21{
22 let lhs = lhs.consume();
23 let rhs = rhs.consume();
24
25 let item_lhs = lhs.ty;
26 let item_rhs = rhs.ty;
27
28 let vector_size = find_vectorization(item_lhs, item_rhs);
29
30 let item = item_lhs.with_vector_size(vector_size);
31
32 let output = scope.create_local(item);
33 let out = *output;
34
35 let op = func(BinaryOperator { lhs, rhs });
36
37 scope.register(Instruction::new(op, out));
38
39 output
40}
41
42pub(crate) fn index_expand_no_vec<F>(
43 scope: &mut Scope,
44 list: ManagedVariable,
45 index: ManagedVariable,
46 func: F,
47) -> ManagedVariable
48where
49 F: Fn(IndexOperator) -> Operator,
50{
51 let list = list.consume();
52 let index = index.consume();
53
54 let item_lhs = list.ty;
55
56 let item = item_lhs.with_vector_size(0);
57
58 let output = scope.create_local(item);
59 let out = *output;
60
61 let op = func(IndexOperator {
62 list,
63 index,
64 vector_size: 0,
65 unroll_factor: 1,
66 });
67
68 scope.register(Instruction::new(op, out));
69
70 output
71}
72pub(crate) fn index_expand<F, Op>(
73 scope: &mut Scope,
74 list: ManagedVariable,
75 index: ManagedVariable,
76 vector_size: Option<VectorSize>,
77 func: F,
78) -> ManagedVariable
79where
80 F: Fn(IndexOperator) -> Op,
81 Op: Into<Operation>,
82{
83 let list = list.consume();
84 let index = index.consume();
85
86 let item_lhs = list.ty;
87 let item_rhs = index.ty;
88
89 let vec = if let Some(vector_size) = vector_size {
90 vector_size
91 } else {
92 find_vectorization(item_lhs, item_rhs)
93 };
94
95 let item = item_lhs.with_vector_size(vec);
96
97 let output = scope.create_local(item);
98 let out = *output;
99
100 let op = func(IndexOperator {
101 list,
102 index,
103 vector_size: vector_size.unwrap_or(0),
104 unroll_factor: 1,
105 });
106
107 scope.register(Instruction::new(op, out));
108
109 output
110}
111
112pub(crate) fn binary_expand_fixed_output<F>(
113 scope: &mut Scope,
114 lhs: ManagedVariable,
115 rhs: ManagedVariable,
116 out_item: Type,
117 func: F,
118) -> ManagedVariable
119where
120 F: Fn(BinaryOperator) -> Arithmetic,
121{
122 let lhs_var = lhs.consume();
123 let rhs_var = rhs.consume();
124
125 let out = scope.create_local(out_item);
126
127 let out_var = *out;
128
129 let op = func(BinaryOperator {
130 lhs: lhs_var,
131 rhs: rhs_var,
132 });
133
134 scope.register(Instruction::new(op, out_var));
135
136 out
137}
138
139pub(crate) fn cmp_expand<F>(
140 scope: &mut Scope,
141 lhs: ManagedVariable,
142 rhs: ManagedVariable,
143 func: F,
144) -> ManagedVariable
145where
146 F: Fn(BinaryOperator) -> Comparison,
147{
148 let lhs = lhs.consume();
149 let rhs = rhs.consume();
150
151 let item_lhs = lhs.ty;
152 let item_rhs = rhs.ty;
153
154 let vector_size = find_vectorization(item_lhs, item_rhs);
155
156 let out_item = Type::scalar(ElemType::Bool).with_vector_size(vector_size);
157
158 let out = scope.create_local(out_item);
159 let out_var = *out;
160
161 let op = func(BinaryOperator { lhs, rhs });
162
163 scope.register(Instruction::new(op, out_var));
164
165 out
166}
167
168pub(crate) fn assign_op_expand<F, Op>(
169 scope: &mut Scope,
170 lhs: ManagedVariable,
171 rhs: ManagedVariable,
172 func: F,
173) -> ManagedVariable
174where
175 F: Fn(BinaryOperator) -> Op,
176 Op: Into<Operation>,
177{
178 if lhs.is_immutable() {
179 panic!("Can't have a mutable operation on a const variable. Try to use `RuntimeCell`.");
180 }
181 let lhs_var: Variable = *lhs;
182 let rhs: Variable = *rhs;
183
184 let op = func(BinaryOperator { lhs: lhs_var, rhs });
185
186 scope.register(Instruction::new(op, lhs_var));
187
188 lhs
189}
190
191pub fn unary_expand<F, Op>(scope: &mut Scope, input: ManagedVariable, func: F) -> ManagedVariable
192where
193 F: Fn(UnaryOperator) -> Op,
194 Op: Into<Operation>,
195{
196 let input = input.consume();
197 let item = input.ty;
198
199 let out = scope.create_local(item);
200 let out_var = *out;
201
202 let op = func(UnaryOperator { input });
203
204 scope.register(Instruction::new(op, out_var));
205
206 out
207}
208
209pub fn unary_expand_fixed_output<F, Op>(
210 scope: &mut Scope,
211 input: ManagedVariable,
212 out_item: Type,
213 func: F,
214) -> ManagedVariable
215where
216 F: Fn(UnaryOperator) -> Op,
217 Op: Into<Operation>,
218{
219 let input = input.consume();
220 let output = scope.create_local(out_item);
221 let out = *output;
222
223 let op = func(UnaryOperator { input });
224
225 scope.register(Instruction::new(op, out));
226
227 output
228}
229
230pub fn init_expand<F>(
231 scope: &mut Scope,
232 input: ManagedVariable,
233 mutable: bool,
234 func: F,
235) -> ManagedVariable
236where
237 F: Fn(Variable) -> Operation,
238{
239 let input_var: Variable = *input;
240 let item = input.ty;
241
242 let out = if mutable {
243 scope.create_local_mut(item)
244 } else {
245 scope.create_local(item)
246 };
247
248 let out_var = *out;
249
250 let op = func(input_var);
251 scope.register(Instruction::new(op, out_var));
252
253 out
254}
255
256pub(crate) fn find_vectorization(lhs: Type, rhs: Type) -> VectorSize {
257 if matches!(lhs, Type::Scalar(_)) && matches!(rhs, Type::Scalar(_)) {
258 0
259 } else {
260 lhs.vector_size().max(rhs.vector_size())
261 }
262}
263
264pub fn array_assign_binary_op_expand<
265 A: RudaType + RudaIndex,
266 V: RudaType,
267 F: Fn(BinaryOperator) -> Op,
268 Op: Into<Operation>,
269>(
270 scope: &mut Scope,
271 array: NativeExpand<A>,
272 index: NativeExpand<usize>,
273 value: NativeExpand<V>,
274 func: F,
275) where
276 A::Output: RudaType + Sized,
277{
278 let array: ManagedVariable = array.into();
279 let index: ManagedVariable = index.into();
280 let value: ManagedVariable = value.into();
281
282 let array_item = match array.kind {
283 VariableKind::LocalMut { .. } => array.ty.with_vector_size(0),
285 _ => array.ty,
286 };
287 let array_value = scope.create_local(array_item);
288
289 let read = Instruction::new(
290 Operator::Index(IndexOperator {
291 list: *array,
292 index: *index,
293 vector_size: 0,
294 unroll_factor: 1,
295 }),
296 *array_value,
297 );
298 let array_value = array_value.consume();
299 let op_out = scope.create_local(array_item);
300 let calculate = Instruction::new(
301 func(BinaryOperator {
302 lhs: array_value,
303 rhs: *value,
304 }),
305 *op_out,
306 );
307
308 let write = Operator::IndexAssign(IndexAssignOperator {
309 index: *index,
310 value: op_out.consume(),
311 vector_size: 0,
312 unroll_factor: 1,
313 });
314 scope.register(read);
315 scope.register(calculate);
316 scope.register(Instruction::new(write, *array));
317}
318
319pub trait DivCeil: Int + RudaType<ExpandType: DivCeilExpand<Self>> {
320 fn div_ceil(self, divisor: Self) -> Self;
321
322 fn __expand_div_ceil(
323 scope: &mut Scope,
324 a: NativeExpand<Self>,
325 b: NativeExpand<Self>,
326 ) -> NativeExpand<Self> {
327 a.__expand_div_ceil_method(scope, b)
328 }
329}
330
331pub trait DivCeilExpand<E: Int> {
332 fn __expand_div_ceil_method(self, scope: &mut Scope, divisor: Self) -> Self;
333}
334
335impl<E: DivCeil> DivCeilExpand<E> for NativeExpand<E> {
336 fn __expand_div_ceil_method(
337 self,
338 scope: &mut Scope,
339 divisor: NativeExpand<E>,
340 ) -> NativeExpand<E> {
341 div_ceil::expand::<E>(scope, self, divisor)
342 }
343}
344
345macro_rules! impl_div_ceil {
346 ($($ty:ty),*) => {
347 $(
348 impl DivCeil for $ty {
349 #[allow(clippy::manual_div_ceil)] fn div_ceil(self, divisor: Self) -> Self {
351 (self + divisor - 1) / divisor
352 }
353 }
354 )*
355 };
356}
357
358impl_div_ceil!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
359
360impl<E: Int> NativeExpand<E> {
361 pub fn __expand_is_multiple_of_method(
362 self,
363 scope: &mut Scope,
364 factor: NativeExpand<E>,
365 ) -> NativeExpand<bool> {
366 let modulo = rem::expand(scope, self, factor);
367 eq::expand(scope, modulo, E::from_int(0).into())
368 }
369}
370
371#[ruda]
372pub fn div_ceil<E: Int>(a: E, b: E) -> E {
373 (a + b - E::new(1)) / b
374}