diff --git a/nac3artiq/src/builtins.rs b/nac3artiq/src/builtins.rs new file mode 100644 index 000000000..a9cb44850 --- /dev/null +++ b/nac3artiq/src/builtins.rs @@ -0,0 +1,167 @@ +use inkwell::{values::BasicValueEnum, AddressSpace, AtomicOrdering}; +use nac3core::{ + toplevel::GenCall, + typecheck::{ + type_inferencer::PrimitiveStore, + typedef::{FunSignature, FuncArg}, + }, +}; +use rustpython_parser::ast::StrRef; +use std::{collections::HashMap, sync::Arc}; + +// ARTIQ timeline control with now-pinning optimization. +pub fn timeline_builtins(primitive: &PrimitiveStore) -> Vec<(StrRef, FunSignature, Arc)> { + vec![ + ( + "now_mu".into(), + FunSignature { + args: vec![], + ret: primitive.int64, + vars: HashMap::new(), + }, + Arc::new(GenCall::new(Box::new(|ctx, _, _, _| { + let i64_type = ctx.ctx.i64_type(); + let now = ctx + .module + .get_global("now") + .unwrap_or_else(|| ctx.module.add_global(i64_type, None, "now")); + let now_raw = ctx.builder.build_load(now.as_pointer_value(), "now"); + if let BasicValueEnum::IntValue(now_raw) = now_raw { + let i64_32 = i64_type.const_int(32, false).into(); + let now_lo = ctx.builder.build_left_shift(now_raw, i64_32, "now_shl"); + let now_hi = ctx + .builder + .build_right_shift(now_raw, i64_32, false, "now_lshr") + .into(); + Some(ctx.builder.build_or(now_lo, now_hi, "now_or").into()) + } else { + unreachable!() + } + }))), + ), + ( + "at_mu".into(), + FunSignature { + args: vec![FuncArg { + name: "t".into(), + ty: primitive.int64, + default_value: None, + }], + ret: primitive.none, + vars: HashMap::new(), + }, + Arc::new(GenCall::new(Box::new(|ctx, _, _, args| { + let i32_type = ctx.ctx.i32_type(); + let i64_type = ctx.ctx.i64_type(); + let i64_32 = i64_type.const_int(32, false).into(); + if let BasicValueEnum::IntValue(time) = args[0].1 { + let time_hi = ctx.builder.build_int_truncate( + ctx.builder + .build_right_shift(time, i64_32, false, "now_lshr"), + i32_type, + "now_trunc", + ); + let time_lo = ctx.builder.build_int_truncate(time, i32_type, "now_trunc"); + let now = ctx + .module + .get_global("now") + .unwrap_or_else(|| ctx.module.add_global(i64_type, None, "now")); + let now_hiptr = ctx.builder.build_bitcast( + now, + i32_type.ptr_type(AddressSpace::Generic), + "now_bitcast", + ); + if let BasicValueEnum::PointerValue(now_hiptr) = now_hiptr { + let now_loptr = unsafe { + ctx.builder.build_gep( + now_hiptr, + &[i32_type.const_int(1, false).into()], + "now_gep", + ) + }; + ctx.builder + .build_store(now_hiptr, time_hi) + .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) + .unwrap(); + ctx.builder + .build_store(now_loptr, time_lo) + .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) + .unwrap(); + None + } else { + unreachable!(); + } + } else { + unreachable!(); + } + }))), + ), + ( + "delay_mu".into(), + FunSignature { + args: vec![FuncArg { + name: "dt".into(), + ty: primitive.int64, + default_value: None, + }], + ret: primitive.none, + vars: HashMap::new(), + }, + Arc::new(GenCall::new(Box::new(|ctx, _, _, args| { + let i32_type = ctx.ctx.i32_type(); + let i64_type = ctx.ctx.i64_type(); + let i64_32 = i64_type.const_int(32, false).into(); + let now = ctx + .module + .get_global("now") + .unwrap_or_else(|| ctx.module.add_global(i64_type, None, "now")); + let now_raw = ctx.builder.build_load(now.as_pointer_value(), "now"); + if let (BasicValueEnum::IntValue(now_raw), BasicValueEnum::IntValue(dt)) = + (now_raw, args[0].1) + { + let now_lo = ctx.builder.build_left_shift(now_raw, i64_32, "now_shl"); + let now_hi = ctx + .builder + .build_right_shift(now_raw, i64_32, false, "now_lshr") + .into(); + let now_val = ctx.builder.build_or(now_lo, now_hi, "now_or"); + let time = ctx.builder.build_int_add(now_val, dt, "now_add"); + let time_hi = ctx.builder.build_int_truncate( + ctx.builder + .build_right_shift(time, i64_32, false, "now_lshr"), + i32_type, + "now_trunc", + ); + let time_lo = ctx.builder.build_int_truncate(time, i32_type, "now_trunc"); + let now_hiptr = ctx.builder.build_bitcast( + now, + i32_type.ptr_type(AddressSpace::Generic), + "now_bitcast", + ); + if let BasicValueEnum::PointerValue(now_hiptr) = now_hiptr { + let now_loptr = unsafe { + ctx.builder.build_gep( + now_hiptr, + &[i32_type.const_int(1, false).into()], + "now_gep", + ) + }; + ctx.builder + .build_store(now_hiptr, time_hi) + .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) + .unwrap(); + ctx.builder + .build_store(now_loptr, time_lo) + .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) + .unwrap(); + None + } else { + unreachable!(); + } + } else { + unreachable!(); + } + }))), + ), + ] +}