cubecl_core/frontend/operation/
base.rs1use cubecl_ir::{
2 Arithmetic, BinaryOperands, Comparison, ElemType, IndexOperands, Instruction, Memory,
3 Operation, Scope, Type, UnaryOperands, Value, VectorSize,
4};
5use cubecl_macros::cube;
6
7use crate::{self as cubecl, prelude::*};
8
9pub(crate) fn read_value(scope: &Scope, val: Value) -> Value {
10 if let Type::Pointer(inner, _) = val.ty {
11 let out = scope.create_value(*inner);
12 scope.register(Instruction::new(Memory::Load(val), out));
13 out
14 } else {
15 val
16 }
17}
18
19pub(crate) fn binary_expand<F, Op>(scope: &Scope, lhs: Value, rhs: Value, func: F) -> Value
20where
21 F: Fn(BinaryOperands) -> Op,
22 Op: Into<Operation>,
23{
24 let item_lhs = lhs.value_type();
25 let item_rhs = rhs.value_type();
26
27 let vector_size = find_vectorization(item_lhs, item_rhs);
28
29 let item = item_lhs.with_vector_size(vector_size);
30
31 let output = scope.create_value(item);
32
33 let op = func(BinaryOperands { lhs, rhs });
34
35 scope.register(Instruction::new(op, output));
36
37 output
38}
39
40pub(crate) fn index_expand(scope: &Scope, list: Value, index: Value, checked: bool) -> Value {
41 let ty = list.value_type();
42
43 let class = list.address_space();
44 let output = scope.create_value(Type::pointer(ty, class));
45
46 let op = Memory::Index(IndexOperands {
47 list,
48 index,
49 unroll_factor: 1,
50 checked,
51 });
52
53 scope.register(Instruction::new(op, output));
54
55 output
56}
57
58pub(crate) fn binary_expand_fixed_output<F>(
59 scope: &Scope,
60 lhs: Value,
61 rhs: Value,
62 out_item: Type,
63 func: F,
64) -> Value
65where
66 F: Fn(BinaryOperands) -> Arithmetic,
67{
68 let out = scope.create_value(out_item);
69 let op = func(BinaryOperands { lhs, rhs });
70
71 scope.register(Instruction::new(op, out));
72
73 out
74}
75
76pub(crate) fn cmp_expand<F>(scope: &Scope, lhs: Value, rhs: Value, func: F) -> Value
77where
78 F: Fn(BinaryOperands) -> Comparison,
79{
80 let item_lhs = lhs.value_type();
81 let item_rhs = rhs.value_type();
82
83 let vector_size = find_vectorization(item_lhs, item_rhs);
84
85 let out_item = Type::scalar(ElemType::Bool).with_vector_size(vector_size);
86
87 let out = scope.create_value(out_item);
88
89 let op = func(BinaryOperands { lhs, rhs });
90
91 scope.register(Instruction::new(op, out));
92
93 out
94}
95
96pub(crate) fn assign_op_expand<T: CubeType, Op>(
97 scope: &Scope,
98 lhs: &mut NativeExpand<T>,
99 rhs: NativeExpand<T>,
100 func: impl Fn(BinaryOperands) -> Op,
101) where
102 Op: Into<Operation>,
103 NativeExpand<T>: DerefExpand<Target = NativeExpand<T>>,
104{
105 let lhs_value = lhs.__expand_deref_method(scope).expand;
106 let lhs = lhs.expand;
107 let rhs = rhs.expand;
108
109 if lhs.is_immutable() {
110 panic!("Can't have a mutable operation on a const variable. Try to use `RuntimeCell`.");
111 }
112
113 let tmp = scope.create_value(lhs.value_type());
114 let op = func(BinaryOperands {
115 lhs: lhs_value,
116 rhs,
117 });
118
119 scope.register(Instruction::new(op, tmp));
120 assign::expand_element(scope, tmp, lhs);
121}
122
123pub fn unary_expand<F, Op>(scope: &Scope, input: Value, func: F) -> Value
124where
125 F: Fn(UnaryOperands) -> Op,
126 Op: Into<Operation>,
127{
128 let item = input.value_type();
129
130 let out = scope.create_value(item);
131
132 let op = func(UnaryOperands { input });
133
134 scope.register(Instruction::new(op, out));
135
136 out
137}
138
139pub fn unary_expand_fixed_output<F, Op>(
140 scope: &Scope,
141 input: Value,
142 out_item: Type,
143 func: F,
144) -> Value
145where
146 F: Fn(UnaryOperands) -> Op,
147 Op: Into<Operation>,
148{
149 let output = scope.create_value(out_item);
150
151 let op = func(UnaryOperands { input });
152
153 scope.register(Instruction::new(op, output));
154
155 output
156}
157
158pub fn init_expand(scope: &Scope, input: Value, mutable: bool) -> Value {
159 let input = read_value(scope, input);
160 let ty = input.ty;
161
162 let out = if mutable {
163 scope.create_local_mut(ty)
164 } else {
165 scope.create_value(ty)
166 };
167
168 assign::expand_element(scope, input, out);
169
170 out
171}
172
173pub(crate) fn find_vectorization(lhs: Type, rhs: Type) -> VectorSize {
174 if matches!(lhs, Type::Scalar(_)) && matches!(rhs, Type::Scalar(_)) {
175 0
176 } else {
177 lhs.vector_size().max(rhs.vector_size())
178 }
179}
180
181pub fn assign_binary_op_expand<
182 A: CubeType,
183 V: CubeType,
184 F: Fn(BinaryOperands) -> Op,
185 Op: Into<Operation>,
186>(
187 scope: &Scope,
188 lhs: &mut NativeExpand<A>,
189 rhs: NativeExpand<V>,
190 func: F,
191) where
192 NativeExpand<A>: DerefExpand<Target = NativeExpand<A>> + Assign,
193{
194 let lhs_value = lhs.__expand_deref_method(scope).expand;
195 let rhs: Value = rhs.into();
196 let out = scope.create_value(lhs.expand.ty);
197
198 scope.register(Instruction::new(
199 func(BinaryOperands {
200 lhs: lhs_value,
201 rhs,
202 }),
203 out,
204 ));
205 lhs.__expand_assign_method(scope, out.into());
206}
207
208pub trait DivCeil: Int + CubeType<ExpandType: DivCeilExpand<Self>> {
209 fn div_ceil(self, divisor: Self) -> Self;
210
211 fn __expand_div_ceil(
212 scope: &Scope,
213 a: NativeExpand<Self>,
214 b: NativeExpand<Self>,
215 ) -> NativeExpand<Self> {
216 a.__expand_div_ceil_method(scope, b)
217 }
218}
219
220pub trait DivCeilExpand<E: Int> {
221 fn __expand_div_ceil_method(self, scope: &Scope, divisor: Self) -> Self;
222}
223
224impl<E: DivCeil> DivCeilExpand<E> for NativeExpand<E> {
225 fn __expand_div_ceil_method(self, scope: &Scope, divisor: NativeExpand<E>) -> NativeExpand<E> {
226 div_ceil::expand::<E>(scope, self, divisor)
227 }
228}
229
230macro_rules! impl_div_ceil {
231 ($($ty:ty),*) => {
232 $(
233 impl DivCeil for $ty {
234 #[allow(clippy::manual_div_ceil)] fn div_ceil(self, divisor: Self) -> Self {
236 (self + divisor - 1) / divisor
237 }
238 }
239 )*
240 };
241}
242
243impl_div_ceil!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
244
245impl<E: Int> NativeExpand<E> {
246 pub fn __expand_is_multiple_of_method(
247 self,
248 scope: &Scope,
249 factor: NativeExpand<E>,
250 ) -> NativeExpand<bool> {
251 let modulo = self.__expand_rem_method(scope, factor);
252 modulo.__expand_eq_method(scope, &E::from_int(0).into())
253 }
254}
255
256#[cube]
257pub fn div_ceil<E: Int>(a: E, b: E) -> E {
258 (a + b - E::new(1)) / b
259}