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};
struct Insert;
impl Intrinsic for Insert {
fn name(&self) -> &'static str {
"insert"
}
fn arity(&self) -> usize {
3
}
fn result_type(&self, _types: &TypeManager, args: &[TypeId]) -> TypeId {
args[0]
}
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 &[arr, index, val] = args else {
return None;
};
let (ValueId::Bytes(bid), ValueId::Literal(ilit), ValueId::Literal(vlit)) =
(arr, index, val)
else {
return None;
};
let ctx = view.shared();
let arr_ty = ctx.values.bytes[bid].type_id;
let (elem, count) = ctx.types.array_of(arr_ty)?;
let esz = ctx.types.size_of(elem);
let i = ctx.values.literals[ilit].value as usize;
if i >= count {
return None;
}
let v = ctx.values.literals[vlit].value;
let mut data = ctx.values.bytes[bid].data.clone();
let off = i * esz;
let v_bytes = v.to_le_bytes();
data[off..off + esz].copy_from_slice(&v_bytes[..esz]);
let nid = ctx.get_typed_bytes(data, arr_ty);
Some(Simplified::Value(nid))
}
}
register_intrinsic!(Insert);
#[cfg(test)]
mod tests {
use super::*;
use crate::context::Context;
use crate::value::insn::IntrinsicId;
#[test]
fn insert_registered_with_arity_3() {
let id = IntrinsicId::from_name("insert").expect("insert registered");
assert_eq!(id.desc().arity(), 3);
}
#[test]
fn result_type_is_the_array_type() {
let types = TypeManager::default();
let i32 = types.get_or_make_int(4);
let arr = types.get_or_make_array(i32, 5);
let id = IntrinsicId::from_name("insert").unwrap();
assert_eq!(id.desc().result_type(&types, &[arr, i32, i32]), arr);
}
#[test]
fn insert_into_const_bytes_folds() {
let mut ctx = Context::new();
let function = ctx.anon_function();
let i32 = ctx.shared.types.get_or_make_int(4);
let arr_ty = ctx.shared.types.get_or_make_array(i32, 3);
let bid = ctx.get_bytes(vec![0; 12]).id();
if let ValueId::Bytes(b) = bid {
ctx.shared.values.bytes[b].type_id = arr_ty;
}
let i = ctx.get_const(1, 8).id();
let v = ctx.get_const(0xaa, 4).id();
let id = IntrinsicId::from_name("insert").unwrap();
let Some(Simplified::Value(ValueId::Bytes(nb))) = id.desc().simplify(
BodyView::new(&ctx.bodies[function], &ctx.shared, &ctx.interfaces),
id,
12,
&[bid, i, v],
) else {
panic!("insert into const Bytes should fold");
};
assert_eq!(&ctx.shared.values.bytes[nb].data[4..8], &[0xaa, 0, 0, 0]);
}
}