use crate::register_intrinsic;
use crate::types::{TypeId, TypeManager};
use crate::value::ValueId;
use crate::value::insn::{Intrinsic, IntrinsicId, Simplified};
use crate::value::{BodyView, QCodeView};
pub const SPLAT_LITERAL_MAX: usize = 100;
struct Splat;
impl Intrinsic for Splat {
fn name(&self) -> &'static str {
"splat"
}
fn arity(&self) -> usize {
2
}
fn result_type(&self, types: &TypeManager, args: &[TypeId]) -> TypeId {
types
.get_list(args[0], None)
.expect("splat result list type must be published")
}
fn eval(&self, _args: &[(u128, usize)], _out_size: usize) -> Option<u128> {
None
}
fn simplify(
&self,
view: BodyView<'_, '_>,
_id: IntrinsicId,
_out_size: usize,
args: &[ValueId],
) -> Option<Simplified> {
let &[val, count] = args else {
return None;
};
let (ValueId::Literal(vlid), ValueId::Literal(clid)) = (val, count) else {
return None;
};
let ctx = view.shared();
let n = ctx.values.literals[clid].value as usize;
if n == 0 || n > SPLAT_LITERAL_MAX {
return None;
}
let bits = ctx.values.literals[vlid].value;
let elem_type_id = ctx.values.literals[vlid].type_id;
let esz = ctx.types.size_of(elem_type_id);
let elem_ty = ctx.types.get_or_make_int(esz);
let arr_ty = ctx.types.get_or_make_array(elem_ty, n);
let mut data = Vec::with_capacity(n * esz);
for _ in 0..n {
data.extend_from_slice(&bits.to_le_bytes()[..esz]);
}
let bid = ctx.get_typed_bytes(data, arr_ty);
Some(Simplified::Value(bid))
}
}
register_intrinsic!(Splat);
#[cfg(test)]
mod tests {
use crate::value::insn::IntrinsicId;
#[test]
fn splat_registered() {
let id = IntrinsicId::from_name("splat").expect("splat registered");
assert_eq!(id.name(), "splat");
assert_eq!(id.desc().arity(), 2);
}
}