use cubecl::ir::{
ConstantValue, ExpandValue, Scope,
interfaces::{ScalarType, TypedExt},
try_cast_ty,
};
use cubecl::prelude::*;
use cubecl::unexpanded;
pub(crate) trait Integer: Sized {
fn plus(self, _rhs: Self) -> Self {
unexpanded!()
}
fn minus(self, _rhs: Self) -> Self {
unexpanded!()
}
fn times(self, _rhs: Self) -> Self {
unexpanded!()
}
fn divided_by(self, _rhs: Self) -> Self {
unexpanded!()
}
fn remainder(self, _rhs: Self) -> Self {
unexpanded!()
}
fn min_with(self, _rhs: Self) -> Self {
unexpanded!()
}
fn max_with(self, _rhs: Self) -> Self {
unexpanded!()
}
fn cast<To: Int>(self) -> To {
unexpanded!()
}
fn constant(self) -> Option<u64> {
unexpanded!()
}
}
impl Integer for u32 {}
impl Integer for usize {}
impl Integer for i32 {}
pub(crate) trait IntegerSeq<C: Int>: Sized {
fn sum(&self, _picks: Vec<usize>) -> C {
unexpanded!()
}
}
impl<C: Int + Integer> IntegerSeq<C> for Sequence<C> {}
pub(crate) fn constant<C: Int>(e: &NativeExpand<C>) -> Option<u64> {
match e.expand.as_const() {
Some(ConstantValue::UInt(v)) => Some(v),
Some(ConstantValue::Int(v)) if v >= 0 => Some(v as u64),
_ => None,
}
}
fn constant_like<C: Int>(scope: &Scope, v: u64, e: &NativeExpand<C>) -> NativeExpand<C> {
let ty = match e.expand {
ExpandValue::Value(val) => {
let ctx = scope.ctx();
let scalar = val.try_get_scalar_elem_ty(ctx).unwrap().deref(ctx);
try_cast_ty!(scalar, ctx, dyn ScalarType).elem_type(ctx)
}
ExpandValue::Constant { ty, .. } => ty,
};
ExpandValue::constant(v.into(), ty).into()
}
pub(crate) fn fold_add<C: Int>(
scope: &Scope,
lhs: NativeExpand<C>,
rhs: NativeExpand<C>,
) -> NativeExpand<C> {
match (constant(&lhs), constant(&rhs)) {
(Some(a), Some(b)) => constant_like(scope, a + b, &lhs),
(Some(0), None) => rhs,
(None, Some(0)) => lhs,
_ => AddExpand::__expand_add_method(lhs, scope, rhs),
}
}
fn fold_sub<C: Int>(scope: &Scope, lhs: NativeExpand<C>, rhs: NativeExpand<C>) -> NativeExpand<C> {
match (constant(&lhs), constant(&rhs)) {
(Some(a), Some(b)) if a >= b => constant_like(scope, a - b, &lhs),
(None, Some(0)) => lhs,
_ => SubExpand::__expand_sub_method(lhs, scope, rhs),
}
}
pub(crate) fn fold_mul<C: Int>(
scope: &Scope,
lhs: NativeExpand<C>,
rhs: NativeExpand<C>,
) -> NativeExpand<C> {
match (constant(&lhs), constant(&rhs)) {
(Some(a), Some(b)) => constant_like(scope, a * b, &lhs),
(Some(0), None) | (None, Some(0)) => constant_like(scope, 0, &lhs),
(Some(1), None) => rhs,
(None, Some(1)) => lhs,
_ => MulExpand::__expand_mul_method(lhs, scope, rhs),
}
}
fn fold_div<C: Int>(scope: &Scope, lhs: NativeExpand<C>, rhs: NativeExpand<C>) -> NativeExpand<C> {
match (constant(&lhs), constant(&rhs)) {
(Some(a), Some(b)) if b != 0 => constant_like(scope, a / b, &lhs),
(None, Some(1)) => lhs,
(Some(0), None) => constant_like(scope, 0, &lhs),
_ => DivExpand::__expand_div_method(lhs, scope, rhs),
}
}
fn fold_rem<C: Int>(scope: &Scope, lhs: NativeExpand<C>, rhs: NativeExpand<C>) -> NativeExpand<C> {
match (constant(&lhs), constant(&rhs)) {
(Some(a), Some(b)) if b != 0 => constant_like(scope, a % b, &lhs),
(None, Some(1)) | (Some(0), None) => constant_like(scope, 0, &lhs),
_ => RemExpand::__expand_rem_method(lhs, scope, rhs),
}
}
fn fold_min<C: Int>(scope: &Scope, lhs: NativeExpand<C>, rhs: NativeExpand<C>) -> NativeExpand<C> {
match (constant(&lhs), constant(&rhs)) {
(Some(a), Some(b)) => constant_like(scope, a.min(b), &lhs),
_ => C::__expand_min(scope, lhs, rhs),
}
}
fn fold_max<C: Int>(scope: &Scope, lhs: NativeExpand<C>, rhs: NativeExpand<C>) -> NativeExpand<C> {
match (constant(&lhs), constant(&rhs)) {
(Some(a), Some(b)) => constant_like(scope, a.max(b), &lhs),
_ => C::__expand_max(scope, lhs, rhs),
}
}
pub(crate) trait IntegerExpand<C: Int>: Sized {
fn __expand_plus_method(self, scope: &Scope, rhs: Self) -> Self;
fn __expand_minus_method(self, scope: &Scope, rhs: Self) -> Self;
fn __expand_times_method(self, scope: &Scope, rhs: Self) -> Self;
fn __expand_divided_by_method(self, scope: &Scope, rhs: Self) -> Self;
fn __expand_remainder_method(self, scope: &Scope, rhs: Self) -> Self;
fn __expand_min_with_method(self, scope: &Scope, rhs: Self) -> Self;
fn __expand_max_with_method(self, scope: &Scope, rhs: Self) -> Self;
fn __expand_cast_method<To: Int>(self, scope: &Scope) -> NativeExpand<To>;
fn __expand_constant_method(self, scope: &Scope) -> Option<u64>;
}
impl<C: Int> IntegerExpand<C> for NativeExpand<C> {
fn __expand_plus_method(self, scope: &Scope, rhs: Self) -> Self {
fold_add(scope, self, rhs)
}
fn __expand_minus_method(self, scope: &Scope, rhs: Self) -> Self {
fold_sub(scope, self, rhs)
}
fn __expand_times_method(self, scope: &Scope, rhs: Self) -> Self {
fold_mul(scope, self, rhs)
}
fn __expand_divided_by_method(self, scope: &Scope, rhs: Self) -> Self {
fold_div(scope, self, rhs)
}
fn __expand_remainder_method(self, scope: &Scope, rhs: Self) -> Self {
fold_rem(scope, self, rhs)
}
fn __expand_min_with_method(self, scope: &Scope, rhs: Self) -> Self {
fold_min(scope, self, rhs)
}
fn __expand_max_with_method(self, scope: &Scope, rhs: Self) -> Self {
fold_max(scope, self, rhs)
}
fn __expand_cast_method<To: Int>(self, scope: &Scope) -> NativeExpand<To> {
match constant(&self) {
Some(v) => ExpandValue::constant(v.into(), To::elem_type(scope)).into(),
None => To::__expand_cast_from(scope, self),
}
}
fn __expand_constant_method(self, _scope: &Scope) -> Option<u64> {
constant(&self)
}
}
pub(crate) trait IntegerSeqExpand<C: Int>: Sized {
fn __expand_sum_method(&self, scope: &Scope, picks: Vec<usize>) -> NativeExpand<C>;
}
impl<C: Int> IntegerSeqExpand<C> for SequenceExpand<C> {
fn __expand_sum_method(&self, scope: &Scope, picks: Vec<usize>) -> NativeExpand<C> {
let mut acc: NativeExpand<C> =
ExpandValue::constant(0u64.into(), C::elem_type(scope)).into();
for i in picks {
let e = *self.__expand_index_method(scope, NativeExpand::from_lit(scope, i));
acc = fold_add(scope, acc, e);
}
acc
}
}