ruPRIM 0.1.9

Parallel primitives, reductions, scans, and indexing for Ruda.
Documentation
#![cfg(feature = "kernel-ir")]

use ruda_kernel::dsl::prelude::*;
use ruda_kernel::dsl::ir::{Bitwise, Operation, Operator};
use ruprim::collective::decompose::*;
use ruprim::collective::record::*;

ruprim::ruda_record! {
    struct Fields { low: u32, high: u64 }
}
ruprim::ruda_record! {
    struct Nested { fields: Fields, tag: u16 }
}
ruprim::ruda_decomposer!(FieldsBits, FieldsBitsLaunch for Fields { high: u64, low: u32 });

#[ruda]
fn scalar_bit(value: u64, index: usize) -> bool {
    let decomposer = RudaScalarDecomposer {};
    <RudaScalarDecomposer as RudaDecomposer<u64>>::bit(&decomposer, value, index)
}

#[ruda]
fn field_bit(value: u32, index: usize) -> bool {
    let decomposer = FieldsBits {};
    decomposer.bit(Fields { low: value, high: 0u64 }, index)
}

#[test]
fn multi_field_decomposer_expands_without_mutating_constants() {
    let mut scope = Scope::root(false);
    scope.register_type::<usize>(u64::as_type(&scope).storage_type());
    field_bit::expand(&mut scope, 3u32.into(), 0usize.into());
    assert!(!scope.instructions.is_empty());
}

#[test]
fn composite_iterators_remain_launch_arguments() {
    fn launch<T: LaunchArg>() {}
    launch::<RudaZip<RudaNativeRecords, RudaNativeRecords>>();
    launch::<RudaZip<RudaZip<RudaNativeRecords, RudaNativeRecords>, RudaNativeRecords>>();
    launch::<RudaReferences<Nested, RudaNativeRecords>>();
}

#[test]
fn reference_assignment_retains_compile_time_marker() {
    let mut scope = Scope::root(false);
    let first = RudaReference::<Nested>::__expand_new(&mut scope, 64u64.into());
    let second = RudaReference::<Nested>::__expand_new(&mut scope, 128u64.into());
    let mut mutable = first.init_mut(&mut scope);
    mutable.expand_assign(&mut scope, second);
    assert!(!scope.instructions.is_empty());
}

#[test]
fn record_allocations_expand_with_native_addresses() {
    let mut scope = Scope::root(false);
    scope.register_type::<usize>(u32::as_type(&scope).storage_type());
    let array = RudaRecordArray::<Nested>::__expand_new(&mut scope, 3);
    let shared = RudaRecordShared::<Nested>::__expand_new(&mut scope, 3);
    array.__expand_address_method(&mut scope, 1usize.into());
    shared.__expand_address_method(&mut scope, 2usize.into());
    assert_eq!(scope.instructions.iter().filter(|instruction|
        matches!(instruction.operation, Operation::Operator(Operator::NativeAddress(_)))
    ).count(), 2);
}

#[test]
fn scalar_decomposition_uses_matching_shift_types() {
    let mut scope = Scope::root(false);
    scope.register_type::<usize>(u32::as_type(&scope).storage_type());
    scalar_bit::expand(&mut scope, (1u64 << 63).into(), 63usize.into());
    let shifts: Vec<_> = scope.instructions.iter().filter_map(|instruction| {
        if let Operation::Bitwise(Bitwise::ShiftRight(op)) = &instruction.operation {
            Some(op)
        } else { None }
    }).collect();
    assert_eq!(shifts.len(), 1);
    assert_eq!(shifts[0].lhs.ty, shifts[0].rhs.ty);
}

#[test]
fn record_addresses_use_consistent_arithmetic_types() {
    for wide in [false, true] {
        let mut scope = Scope::root(false);
        let ty = if wide { u64::as_type(&scope) } else { u32::as_type(&scope) };
        scope.register_type::<usize>(ty.storage_type());
        let array = RudaRecordArray::<Nested>::__expand_new(&mut scope, 3);
        let index = NativeExpand::from_lit(&scope, 1usize);
        let address = array.__expand_address_method(&mut scope, index);
        Nested::__expand_load(&mut scope, address);
        let shared = RudaRecordShared::<Nested>::__expand_new(&mut scope, 3);
        shared.__expand_address_method(&mut scope, 0usize.into());
        for instruction in &scope.instructions {
            use ruda_kernel::dsl::ir::Arithmetic;
            if let Operation::Arithmetic(Arithmetic::Add(op) | Arithmetic::Sub(op) | Arithmetic::Mul(op) | Arithmetic::Div(op)) = &instruction.operation {
                assert_eq!(op.lhs.ty, op.rhs.ty, "{instruction:?}");
            }
        }
    }
}