use core::{fmt::Display, hash::Hash};
use crate::{
FloatKind, IntKind, Scope, TypeHash,
attributes::{BoolAttr, FloatAttr, IndexAttr},
dialect::memory::LoadOp,
interfaces::TypedExt,
};
use super::{ElemType, Type, UIntKind};
use cubecl_common::{e2m1, e4m3, e5m2, ue8m0};
use derive_more::From;
use float_ord::FloatOrd;
use pliron::{
attribute::AttrObj,
builtin::{attributes::IntegerAttr, ops::ConstantOp},
context::Context,
derive::format,
r#type::TypedHandle,
utils::apint::{APInt, bw},
value::Value,
};
pub fn read_value(scope: &Scope, val: Value) -> Value {
if val.is_ptr(scope.ctx()) {
let op = LoadOp::new(scope.ctx_mut(), val);
scope.register_with_result(&op)
} else {
val
}
}
impl ExpandValue {
pub fn new(value: Value) -> Self {
Self::Value(value)
}
pub fn constant(value: ConstantValue, ty: impl Into<ElemType>) -> Self {
let ty = ty.into();
let value = value.cast_to(ty);
Self::Constant { value, ty }
}
pub fn read_value(&self, scope: &Scope) -> Value {
let val = self.value(scope);
read_value(scope, val)
}
pub fn value(&self, scope: &Scope) -> Value {
match self {
ExpandValue::Value(value) => *value,
ExpandValue::Constant { value, ty } => {
let ctx = scope.ctx_mut();
let value = value.as_attribute(ctx, *ty);
let op = ConstantOp::new(scope.ctx_mut(), value);
scope.register_with_result(&op)
}
}
}
}
#[derive(Debug, Clone, Copy, TypeHash, PartialEq, Eq, Hash)]
pub enum ExpandValue {
Value(Value),
Constant { value: ConstantValue, ty: ElemType },
}
impl From<Value> for ExpandValue {
fn from(value: Value) -> Self {
Self::Value(value)
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TypeHash, PartialOrd, Ord)]
#[format]
#[repr(u32)]
pub enum Builtin {
UnitPos,
UnitPosX,
UnitPosY,
UnitPosZ,
CubePosCluster,
CubePosClusterX,
CubePosClusterY,
CubePosClusterZ,
CubePos,
CubePosX,
CubePosY,
CubePosZ,
CubeDim,
CubeDimX,
CubeDimY,
CubeDimZ,
CubeClusterDim,
CubeClusterDimX,
CubeClusterDimY,
CubeClusterDimZ,
CubeCount,
CubeCountX,
CubeCountY,
CubeCountZ,
PlaneDim,
PlanePos,
UnitPosPlane,
AbsolutePos,
AbsolutePosX,
AbsolutePosY,
AbsolutePosZ,
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, TypeHash, PartialEq, PartialOrd, From)]
#[allow(missing_docs, clippy::derive_ord_xor_partial_ord)]
pub enum ConstantValue {
Int(i64),
Float(f64),
UInt(u64),
Bool(bool),
}
impl Ord for ConstantValue {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
match (self, other) {
(ConstantValue::Float(this), ConstantValue::Float(other)) => {
FloatOrd(*this).cmp(&FloatOrd(*other))
}
_ => self.partial_cmp(other).unwrap(),
}
}
}
impl Eq for ConstantValue {}
impl Hash for ConstantValue {
fn hash<H: core::hash::Hasher>(&self, ra_expand_state: &mut H) {
core::mem::discriminant(self).hash(ra_expand_state);
match self {
ConstantValue::Int(f0) => {
f0.hash(ra_expand_state);
}
ConstantValue::Float(f0) => {
FloatOrd(*f0).hash(ra_expand_state);
}
ConstantValue::UInt(f0) => {
f0.hash(ra_expand_state);
}
ConstantValue::Bool(f0) => {
f0.hash(ra_expand_state);
}
}
}
}
impl ConstantValue {
pub fn try_as_usize(&self) -> Option<usize> {
match self {
ConstantValue::UInt(val) => Some(*val as usize),
ConstantValue::Int(val) => Some(*val as usize),
ConstantValue::Float(_) => None,
ConstantValue::Bool(_) => None,
}
}
pub fn as_usize(&self) -> usize {
match self {
ConstantValue::UInt(val) => *val as usize,
ConstantValue::Int(val) => *val as usize,
ConstantValue::Float(val) => *val as usize,
ConstantValue::Bool(val) => *val as usize,
}
}
pub fn try_as_u32(&self) -> Option<u32> {
self.try_as_u64().map(|it| it as u32)
}
pub fn as_u32(&self) -> u32 {
self.as_u64() as u32
}
pub fn try_as_u64(&self) -> Option<u64> {
match self {
ConstantValue::UInt(val) => Some(*val),
ConstantValue::Int(val) => Some(*val as u64),
ConstantValue::Float(_) => None,
ConstantValue::Bool(_) => None,
}
}
pub fn as_u64(&self) -> u64 {
match self {
ConstantValue::UInt(val) => *val,
ConstantValue::Int(val) => *val as u64,
ConstantValue::Float(val) => *val as u64,
ConstantValue::Bool(val) => *val as u64,
}
}
pub fn try_as_i64(&self) -> Option<i64> {
match self {
ConstantValue::UInt(val) => Some(*val as i64),
ConstantValue::Int(val) => Some(*val),
ConstantValue::Float(_) => None,
ConstantValue::Bool(_) => None,
}
}
pub fn as_i128(&self) -> i128 {
match self {
ConstantValue::UInt(val) => *val as i128,
ConstantValue::Int(val) => *val as i128,
ConstantValue::Float(val) => *val as i128,
ConstantValue::Bool(val) => *val as i128,
}
}
pub fn as_i64(&self) -> i64 {
match self {
ConstantValue::UInt(val) => *val as i64,
ConstantValue::Int(val) => *val,
ConstantValue::Float(val) => *val as i64,
ConstantValue::Bool(val) => *val as i64,
}
}
pub fn as_i32(&self) -> i32 {
match self {
ConstantValue::UInt(val) => *val as i32,
ConstantValue::Int(val) => *val as i32,
ConstantValue::Float(val) => *val as i32,
ConstantValue::Bool(val) => *val as i32,
}
}
pub fn try_as_f64(&self) -> Option<f64> {
match self {
ConstantValue::Float(val) => Some(*val),
_ => None,
}
}
pub fn as_f64(&self) -> f64 {
match self {
ConstantValue::UInt(val) => *val as f64,
ConstantValue::Int(val) => *val as f64,
ConstantValue::Float(val) => *val,
ConstantValue::Bool(val) => *val as u8 as f64,
}
}
pub fn try_as_bool(&self) -> Option<bool> {
match self {
ConstantValue::Bool(val) => Some(*val),
_ => None,
}
}
pub fn as_bool(&self) -> bool {
match self {
ConstantValue::UInt(val) => *val != 0,
ConstantValue::Int(val) => *val != 0,
ConstantValue::Float(val) => *val != 0.,
ConstantValue::Bool(val) => *val,
}
}
pub fn as_attribute(&self, ctx: &Context, elem: ElemType) -> AttrObj {
let ty = elem.to_type(ctx);
match self {
ConstantValue::Int(value) => {
let value = APInt::from_i64(*value, bw(ty.size_bits(ctx)));
IntegerAttr::new(TypedHandle::from_handle(ty, ctx).unwrap(), value).into()
}
ConstantValue::UInt(value) if elem == ElemType::Index => {
IndexAttr::new(*value as usize).into()
}
ConstantValue::UInt(value) => {
let value = APInt::from_u64(*value, bw(ty.size_bits(ctx)));
IntegerAttr::new(TypedHandle::from_handle(ty, ctx).unwrap(), value).into()
}
ConstantValue::Float(value) => FloatAttr::from_f64(ctx, ty, *value).into(),
ConstantValue::Bool(value) => BoolAttr::new(*value).into(),
}
}
pub fn is_zero(&self) -> bool {
match self {
ConstantValue::Int(val) => *val == 0,
ConstantValue::Float(val) => *val == 0.0,
ConstantValue::UInt(val) => *val == 0,
ConstantValue::Bool(val) => !*val,
}
}
pub fn is_one(&self) -> bool {
match self {
ConstantValue::Int(val) => *val == 1,
ConstantValue::Float(val) => *val == 1.0,
ConstantValue::UInt(val) => *val == 1,
ConstantValue::Bool(val) => *val,
}
}
pub fn cast_to(&self, other: impl Into<Type>) -> ConstantValue {
match other.into().elem_type() {
ElemType::Index => self.as_u64().into(),
ElemType::Float(kind) => match kind {
FloatKind::E2M1 => e2m1::from_f64(self.as_f64()).to_f64(),
FloatKind::E2M1x2 => e2m1::from_f64(self.as_f64()).to_f64(),
FloatKind::E2M3 | FloatKind::E3M2 => {
unimplemented!("FP6 constants not yet supported")
}
FloatKind::E4M3 => e4m3::from_f64(self.as_f64()).to_f64(),
FloatKind::E5M2 => e5m2::from_f64(self.as_f64()).to_f64(),
FloatKind::UE8M0 => ue8m0::from_f64(self.as_f64()).to_f64(),
FloatKind::F16 => half::f16::from_f64(self.as_f64()).to_f64(),
FloatKind::BF16 => half::bf16::from_f64(self.as_f64()).to_f64(),
FloatKind::Flex32 | FloatKind::TF32 | FloatKind::F32 => self.as_f64() as f32 as f64,
FloatKind::F64 => self.as_f64(),
}
.into(),
ElemType::Int(kind) => match kind {
IntKind::I8 => self.as_i64() as i8 as i64,
IntKind::I16 => self.as_i64() as i16 as i64,
IntKind::I32 => self.as_i64() as i32 as i64,
IntKind::I64 => self.as_i64(),
}
.into(),
ElemType::UInt(kind) => match kind {
UIntKind::U8 => self.as_u64() as u8 as u64,
UIntKind::U16 => self.as_u64() as u16 as u64,
UIntKind::U32 => self.as_u64() as u32 as u64,
UIntKind::U64 => self.as_u64(),
}
.into(),
ElemType::Bool => self.as_bool().into(),
}
}
}
impl Display for ConstantValue {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
ConstantValue::Int(val) => write!(f, "{val}"),
ConstantValue::Float(val) => write!(f, "{val:?}"),
ConstantValue::UInt(val) => write!(f, "{val}"),
ConstantValue::Bool(val) => write!(f, "{val}"),
}
}
}
impl ExpandValue {
pub fn as_const(&self) -> Option<ConstantValue> {
match self {
ExpandValue::Constant { value, .. } => Some(*value),
_ => None,
}
}
}
impl Display for ExpandValue {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
ExpandValue::Constant { value, ty } => write!(f, "{ty}({value})"),
ExpandValue::Value(value) => write!(f, "{value:?}"),
}
}
}
impl From<&ExpandValue> for ExpandValue {
fn from(value: &ExpandValue) -> Self {
*value
}
}