1use core::{fmt::Display, hash::Hash};
2
3use crate::{
4 FloatKind, IntKind, Scope, TypeHash,
5 attributes::{BoolAttr, FloatAttr, IndexAttr},
6 dialect::memory::LoadOp,
7 interfaces::TypedExt,
8};
9
10use super::{ElemType, Type, UIntKind};
11use cubecl_common::{e2m1, e4m3, e5m2, ue8m0};
12use derive_more::From;
13use float_ord::FloatOrd;
14use pliron::{
15 attribute::AttrObj,
16 builtin::{attributes::IntegerAttr, ops::ConstantOp},
17 context::Context,
18 derive::format,
19 r#type::TypedHandle,
20 utils::apint::{APInt, bw},
21 value::Value,
22};
23
24pub fn read_value(scope: &Scope, val: Value) -> Value {
25 if val.is_ptr(scope.ctx()) {
26 let op = LoadOp::new(scope.ctx_mut(), val);
27 scope.register_with_result(&op)
28 } else {
29 val
30 }
31}
32
33impl ExpandValue {
34 pub fn new(value: Value) -> Self {
35 Self::Value(value)
36 }
37
38 pub fn constant(value: ConstantValue, ty: impl Into<ElemType>) -> Self {
39 let ty = ty.into();
40 let value = value.cast_to(ty);
41 Self::Constant { value, ty }
42 }
43
44 pub fn read_value(&self, scope: &Scope) -> Value {
45 let val = self.value(scope);
46 read_value(scope, val)
47 }
48
49 pub fn value(&self, scope: &Scope) -> Value {
50 match self {
51 ExpandValue::Value(value) => *value,
52 ExpandValue::Constant { value, ty } => {
53 let ctx = scope.ctx_mut();
54 let value = value.as_attribute(ctx, *ty);
55 let op = ConstantOp::new(scope.ctx_mut(), value);
56 scope.register_with_result(&op)
57 }
58 }
59 }
60}
61
62#[derive(Debug, Clone, Copy, TypeHash, PartialEq, Eq, Hash)]
63pub enum ExpandValue {
64 Value(Value),
65 Constant { value: ConstantValue, ty: ElemType },
66}
67
68impl From<Value> for ExpandValue {
69 fn from(value: Value) -> Self {
70 Self::Value(value)
71 }
72}
73
74#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
75#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TypeHash, PartialOrd, Ord)]
76#[format]
77#[repr(u32)]
78pub enum Builtin {
79 UnitPos,
80 UnitPosX,
81 UnitPosY,
82 UnitPosZ,
83 CubePosCluster,
84 CubePosClusterX,
85 CubePosClusterY,
86 CubePosClusterZ,
87 CubePos,
88 CubePosX,
89 CubePosY,
90 CubePosZ,
91 CubeDim,
92 CubeDimX,
93 CubeDimY,
94 CubeDimZ,
95 CubeClusterDim,
96 CubeClusterDimX,
97 CubeClusterDimY,
98 CubeClusterDimZ,
99 CubeCount,
100 CubeCountX,
101 CubeCountY,
102 CubeCountZ,
103 PlaneDim,
104 PlanePos,
105 UnitPosPlane,
106 AbsolutePos,
107 AbsolutePosX,
108 AbsolutePosY,
109 AbsolutePosZ,
110}
111
112#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
116#[derive(Debug, Clone, Copy, TypeHash, PartialEq, PartialOrd, From)]
117#[allow(missing_docs, clippy::derive_ord_xor_partial_ord)]
118pub enum ConstantValue {
119 Int(i64),
120 Float(f64),
121 UInt(u64),
122 Bool(bool),
123}
124
125impl Ord for ConstantValue {
126 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
127 match (self, other) {
130 (ConstantValue::Float(this), ConstantValue::Float(other)) => {
131 FloatOrd(*this).cmp(&FloatOrd(*other))
132 }
133 _ => self.partial_cmp(other).unwrap(),
134 }
135 }
136}
137
138impl Eq for ConstantValue {}
139impl Hash for ConstantValue {
140 fn hash<H: core::hash::Hasher>(&self, ra_expand_state: &mut H) {
141 core::mem::discriminant(self).hash(ra_expand_state);
142 match self {
143 ConstantValue::Int(f0) => {
144 f0.hash(ra_expand_state);
145 }
146 ConstantValue::Float(f0) => {
147 FloatOrd(*f0).hash(ra_expand_state);
148 }
149 ConstantValue::UInt(f0) => {
150 f0.hash(ra_expand_state);
151 }
152 ConstantValue::Bool(f0) => {
153 f0.hash(ra_expand_state);
154 }
155 }
156 }
157}
158
159impl ConstantValue {
160 pub fn try_as_usize(&self) -> Option<usize> {
164 match self {
165 ConstantValue::UInt(val) => Some(*val as usize),
166 ConstantValue::Int(val) => Some(*val as usize),
167 ConstantValue::Float(_) => None,
168 ConstantValue::Bool(_) => None,
169 }
170 }
171
172 pub fn as_usize(&self) -> usize {
174 match self {
175 ConstantValue::UInt(val) => *val as usize,
176 ConstantValue::Int(val) => *val as usize,
177 ConstantValue::Float(val) => *val as usize,
178 ConstantValue::Bool(val) => *val as usize,
179 }
180 }
181
182 pub fn try_as_u32(&self) -> Option<u32> {
186 self.try_as_u64().map(|it| it as u32)
187 }
188
189 pub fn as_u32(&self) -> u32 {
193 self.as_u64() as u32
194 }
195
196 pub fn try_as_u64(&self) -> Option<u64> {
200 match self {
201 ConstantValue::UInt(val) => Some(*val),
202 ConstantValue::Int(val) => Some(*val as u64),
203 ConstantValue::Float(_) => None,
204 ConstantValue::Bool(_) => None,
205 }
206 }
207
208 pub fn as_u64(&self) -> u64 {
210 match self {
211 ConstantValue::UInt(val) => *val,
212 ConstantValue::Int(val) => *val as u64,
213 ConstantValue::Float(val) => *val as u64,
214 ConstantValue::Bool(val) => *val as u64,
215 }
216 }
217
218 pub fn try_as_i64(&self) -> Option<i64> {
222 match self {
223 ConstantValue::UInt(val) => Some(*val as i64),
224 ConstantValue::Int(val) => Some(*val),
225 ConstantValue::Float(_) => None,
226 ConstantValue::Bool(_) => None,
227 }
228 }
229
230 pub fn as_i128(&self) -> i128 {
232 match self {
233 ConstantValue::UInt(val) => *val as i128,
234 ConstantValue::Int(val) => *val as i128,
235 ConstantValue::Float(val) => *val as i128,
236 ConstantValue::Bool(val) => *val as i128,
237 }
238 }
239
240 pub fn as_i64(&self) -> i64 {
242 match self {
243 ConstantValue::UInt(val) => *val as i64,
244 ConstantValue::Int(val) => *val,
245 ConstantValue::Float(val) => *val as i64,
246 ConstantValue::Bool(val) => *val as i64,
247 }
248 }
249
250 pub fn as_i32(&self) -> i32 {
252 match self {
253 ConstantValue::UInt(val) => *val as i32,
254 ConstantValue::Int(val) => *val as i32,
255 ConstantValue::Float(val) => *val as i32,
256 ConstantValue::Bool(val) => *val as i32,
257 }
258 }
259
260 pub fn try_as_f64(&self) -> Option<f64> {
264 match self {
265 ConstantValue::Float(val) => Some(*val),
266 _ => None,
267 }
268 }
269
270 pub fn as_f64(&self) -> f64 {
272 match self {
273 ConstantValue::UInt(val) => *val as f64,
274 ConstantValue::Int(val) => *val as f64,
275 ConstantValue::Float(val) => *val,
276 ConstantValue::Bool(val) => *val as u8 as f64,
277 }
278 }
279
280 pub fn try_as_bool(&self) -> Option<bool> {
282 match self {
283 ConstantValue::Bool(val) => Some(*val),
284 _ => None,
285 }
286 }
287
288 pub fn as_bool(&self) -> bool {
292 match self {
293 ConstantValue::UInt(val) => *val != 0,
294 ConstantValue::Int(val) => *val != 0,
295 ConstantValue::Float(val) => *val != 0.,
296 ConstantValue::Bool(val) => *val,
297 }
298 }
299
300 pub fn as_attribute(&self, ctx: &Context, elem: ElemType) -> AttrObj {
301 let ty = elem.to_type(ctx);
302 match self {
303 ConstantValue::Int(value) => {
304 let value = APInt::from_i64(*value, bw(ty.size_bits(ctx)));
305 IntegerAttr::new(TypedHandle::from_handle(ty, ctx).unwrap(), value).into()
306 }
307 ConstantValue::UInt(value) if elem == ElemType::Index => {
308 IndexAttr::new(*value as usize).into()
309 }
310 ConstantValue::UInt(value) => {
311 let value = APInt::from_u64(*value, bw(ty.size_bits(ctx)));
312 IntegerAttr::new(TypedHandle::from_handle(ty, ctx).unwrap(), value).into()
313 }
314 ConstantValue::Float(value) => FloatAttr::from_f64(ctx, ty, *value).into(),
315 ConstantValue::Bool(value) => BoolAttr::new(*value).into(),
316 }
317 }
318
319 pub fn is_zero(&self) -> bool {
320 match self {
321 ConstantValue::Int(val) => *val == 0,
322 ConstantValue::Float(val) => *val == 0.0,
323 ConstantValue::UInt(val) => *val == 0,
324 ConstantValue::Bool(val) => !*val,
325 }
326 }
327
328 pub fn is_one(&self) -> bool {
329 match self {
330 ConstantValue::Int(val) => *val == 1,
331 ConstantValue::Float(val) => *val == 1.0,
332 ConstantValue::UInt(val) => *val == 1,
333 ConstantValue::Bool(val) => *val,
334 }
335 }
336
337 pub fn cast_to(&self, other: impl Into<Type>) -> ConstantValue {
338 match other.into().elem_type() {
339 ElemType::Index => self.as_u64().into(),
340 ElemType::Float(kind) => match kind {
341 FloatKind::E2M1 => e2m1::from_f64(self.as_f64()).to_f64(),
342 FloatKind::E2M1x2 => e2m1::from_f64(self.as_f64()).to_f64(),
343 FloatKind::E2M3 | FloatKind::E3M2 => {
344 unimplemented!("FP6 constants not yet supported")
345 }
346 FloatKind::E4M3 => e4m3::from_f64(self.as_f64()).to_f64(),
347 FloatKind::E5M2 => e5m2::from_f64(self.as_f64()).to_f64(),
348 FloatKind::UE8M0 => ue8m0::from_f64(self.as_f64()).to_f64(),
349 FloatKind::F16 => half::f16::from_f64(self.as_f64()).to_f64(),
350 FloatKind::BF16 => half::bf16::from_f64(self.as_f64()).to_f64(),
351 FloatKind::Flex32 | FloatKind::TF32 | FloatKind::F32 => self.as_f64() as f32 as f64,
352 FloatKind::F64 => self.as_f64(),
353 }
354 .into(),
355 ElemType::Int(kind) => match kind {
356 IntKind::I8 => self.as_i64() as i8 as i64,
357 IntKind::I16 => self.as_i64() as i16 as i64,
358 IntKind::I32 => self.as_i64() as i32 as i64,
359 IntKind::I64 => self.as_i64(),
360 }
361 .into(),
362 ElemType::UInt(kind) => match kind {
363 UIntKind::U8 => self.as_u64() as u8 as u64,
364 UIntKind::U16 => self.as_u64() as u16 as u64,
365 UIntKind::U32 => self.as_u64() as u32 as u64,
366 UIntKind::U64 => self.as_u64(),
367 }
368 .into(),
369 ElemType::Bool => self.as_bool().into(),
370 }
371 }
372}
373
374impl Display for ConstantValue {
375 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
376 match self {
377 ConstantValue::Int(val) => write!(f, "{val}"),
378 ConstantValue::Float(val) => write!(f, "{val:?}"),
379 ConstantValue::UInt(val) => write!(f, "{val}"),
380 ConstantValue::Bool(val) => write!(f, "{val}"),
381 }
382 }
383}
384
385impl ExpandValue {
386 pub fn as_const(&self) -> Option<ConstantValue> {
387 match self {
388 ExpandValue::Constant { value, .. } => Some(*value),
389 _ => None,
390 }
391 }
392}
393
394impl Display for ExpandValue {
395 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
396 match self {
397 ExpandValue::Constant { value, ty } => write!(f, "{ty}({value})"),
398 ExpandValue::Value(value) => write!(f, "{value:?}"),
399 }
400 }
401}
402
403impl From<&ExpandValue> for ExpandValue {
405 fn from(value: &ExpandValue) -> Self {
406 *value
407 }
408}