Skip to main content

xlsynth/
lib_support.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Support functions that are not exposed as primary APIs from `lib.rs` but
4//! support the implementation of functions exposed via `lib.rs`.`
5//!
6//! (Things in this module are generally crate-visible vs public to provide that
7//! support.)
8#![allow(clippy::arc_with_non_send_sync)]
9
10use std::{
11    ffi::{CStr, CString},
12    sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
13};
14
15use xlsynth_sys::{
16    CIrAnalysis, CIrBValue, CIrBits, CIrFunction, CIrFunctionJit, CIrFunctionType, CIrIntervalSet,
17    CIrPackage, CIrType, CIrValue, CScheduleAndCodegenResult, CTraceMessage, XlsFormatPreference,
18};
19
20use crate::{
21    ir_package::{IrPackagePtr, IrType, ScheduleAndCodegenResult},
22    IrBits, IrFunction, IrValue, XlsynthError,
23};
24
25// Wrapper around the raw pointer that frees (i.e. when the wrapping refcount
26// drops to zero).
27pub(crate) struct IrFnBuilderPtr {
28    pub(crate) ptr: *mut xlsynth_sys::CIrFunctionBuilder,
29}
30
31impl Drop for IrFnBuilderPtr {
32    fn drop(&mut self) {
33        if !self.ptr.is_null() {
34            unsafe {
35                xlsynth_sys::xls_function_builder_free(self.ptr);
36            }
37        }
38    }
39}
40
41// Wrapper around the raw pointer that frees (i.e. when the wrapping refcount
42// drops to zero).
43pub(crate) struct BValuePtr {
44    pub(crate) ptr: *mut CIrBValue,
45}
46
47impl Drop for BValuePtr {
48    fn drop(&mut self) {
49        unsafe {
50            xlsynth_sys::xls_bvalue_free(self.ptr);
51        }
52    }
53}
54
55/// Macro for performing FFI calls to fallible functions with a trailing output
56/// parameter.
57///
58/// You call it by passing in the FFI function, its regular arguments,
59/// then a semicolon and the identifier to populate with the output.
60/// It returns a Result<(), XlsynthError>.
61///
62/// For instance, calling:
63/// ```rust-snippet
64/// let mut ir_out: *mut c_char = std::ptr::null_mut();
65/// xls_call!(xlsynth_sys::xls_optimize_ir, ir.as_ptr(), top.as_ptr(); ir_out)?;
66/// ```
67/// will call the FFI function with the arguments and automatically convert the
68/// error if it occurs.
69macro_rules! xls_ffi_call {
70    ($func:path $(, $arg:expr )* ; $out:ident) => {{
71        unsafe {
72            let mut error_out: *mut std::os::raw::c_char = std::ptr::null_mut();
73            let success = $func($($arg,)* &mut error_out, &mut $out);
74            if success {
75                Ok(())
76            } else {
77                Err(XlsynthError(c_str_to_rust(error_out)))
78            }
79        }
80    }};
81}
82
83// Variant of the above macro for when we have no return value.
84macro_rules! xls_ffi_call_noreturn {
85    ($func:path $(, $arg:expr )*) => {{
86        unsafe {
87            let mut error_out: *mut std::os::raw::c_char = std::ptr::null_mut();
88            let success = $func($($arg,)* &mut error_out);
89            if success {
90                Ok(())
91            } else {
92                Err(XlsynthError(c_str_to_rust(error_out)))
93            }
94        }
95    }};
96}
97
98pub(crate) fn xls_package_to_string(p: *const CIrPackage) -> Result<String, XlsynthError> {
99    unsafe {
100        let mut c_str_out: *mut std::os::raw::c_char = std::ptr::null_mut();
101        let success = xlsynth_sys::xls_package_to_string(p, &mut c_str_out);
102        if success {
103            Ok(c_str_to_rust(c_str_out))
104        } else {
105            Err(XlsynthError(
106                "Failed to convert XLS package to string via C API".to_string(),
107            ))
108        }
109    }
110}
111
112pub(crate) fn xls_function_to_string(f: *const CIrFunction) -> Result<String, XlsynthError> {
113    unsafe {
114        let mut c_str_out: *mut std::os::raw::c_char = std::ptr::null_mut();
115        let success = xlsynth_sys::xls_function_to_string(f, &mut c_str_out);
116        if success {
117            Ok(c_str_to_rust(c_str_out))
118        } else {
119            Err(XlsynthError(
120                "Failed to convert XLS function to string via C API".to_string(),
121            ))
122        }
123    }
124}
125
126pub(crate) unsafe fn c_str_to_rust_no_dealloc(xls_c_str: *mut std::os::raw::c_char) -> String {
127    if xls_c_str.is_null() {
128        String::new()
129    } else {
130        let c_str: &CStr = CStr::from_ptr(xls_c_str);
131        String::from_utf8_lossy(c_str.to_bytes()).to_string()
132    }
133}
134
135/// Converts a C string that was given from the XLS library into a Rust string
136/// and deallocates the original C string.
137pub(crate) unsafe fn c_str_to_rust(xls_c_str: *mut std::os::raw::c_char) -> String {
138    let result = c_str_to_rust_no_dealloc(xls_c_str);
139
140    // We release the C string via a call to the XLS library so that it can use the
141    // same allocator it used to allocate the string for deallocation and we don't
142    // need to assume the Rust code and dynmic library are using the same underlying
143    // allocator.
144    xlsynth_sys::xls_c_str_free(xls_c_str);
145    result
146}
147
148/// Returns a CString built from the given string and a pointer to its contents.
149/// The CString must be kept alive as long as the pointer is used.
150fn cstring_and_ptr(name: &str) -> (CString, *const std::os::raw::c_char) {
151    let cstr = CString::new(name).unwrap();
152    let ptr = cstr.as_ptr();
153    (cstr, ptr)
154}
155
156/// Like [`cstring_and_ptr`] but for optional strings. The returned pointer is
157/// null if the option is `None`.
158fn optional_cstring_and_ptr(name: Option<&str>) -> (Option<CString>, *const std::os::raw::c_char) {
159    if let Some(s) = name {
160        let cstr = CString::new(s).unwrap();
161        let ptr = cstr.as_ptr();
162        (Some(cstr), ptr)
163    } else {
164        (None, std::ptr::null())
165    }
166}
167
168pub(crate) fn xls_value_free(p: *mut CIrValue) {
169    unsafe { xlsynth_sys::xls_value_free(p) }
170}
171
172pub(crate) fn xls_package_free(p: *mut CIrPackage) {
173    unsafe { xlsynth_sys::xls_package_free(p) }
174}
175
176pub(crate) fn xls_value_to_string(p: *mut CIrValue) -> Result<String, XlsynthError> {
177    unsafe {
178        let mut c_str_out: *mut std::os::raw::c_char = std::ptr::null_mut();
179        let success = xlsynth_sys::xls_value_to_string(p, &mut c_str_out);
180        if success {
181            Ok(c_str_to_rust(c_str_out))
182        } else {
183            Err(XlsynthError(
184                "Failed to convert XLS value to string via C API".to_string(),
185            ))
186        }
187    }
188}
189
190pub(crate) fn xls_value_get_element(
191    p: *mut CIrValue,
192    index: usize,
193) -> Result<IrValue, XlsynthError> {
194    let mut element_out: *mut CIrValue = std::ptr::null_mut();
195    xls_ffi_call!(xlsynth_sys::xls_value_get_element, p, index; element_out)?;
196    Ok(IrValue { ptr: element_out })
197}
198
199pub(crate) fn xls_value_get_element_count(p: *const CIrValue) -> Result<usize, XlsynthError> {
200    let mut count: i64 = 0;
201    xls_ffi_call!(xlsynth_sys::xls_value_get_element_count, p; count)?;
202    Ok(count as usize)
203}
204
205pub(crate) fn xls_value_make_ubits(value: u64, bit_count: usize) -> Result<IrValue, XlsynthError> {
206    let mut result: *mut CIrValue = std::ptr::null_mut();
207    xls_ffi_call!(xlsynth_sys::xls_value_make_ubits, bit_count as i64, value; result)?;
208    Ok(IrValue { ptr: result })
209}
210
211pub(crate) fn xls_value_make_sbits(value: i64, bit_count: usize) -> Result<IrValue, XlsynthError> {
212    let mut result: *mut CIrValue = std::ptr::null_mut();
213    xls_ffi_call!(xlsynth_sys::xls_value_make_sbits, bit_count as i64, value; result)?;
214    Ok(IrValue { ptr: result })
215}
216
217pub(crate) fn xls_value_make_token() -> IrValue {
218    let result = unsafe { xlsynth_sys::xls_value_make_token() };
219    assert!(!result.is_null());
220    IrValue { ptr: result }
221}
222
223pub(crate) fn xls_value_make_tuple(elements: &[IrValue]) -> IrValue {
224    unsafe {
225        let elements_ptrs: Vec<*const CIrValue> =
226            elements.iter().map(|v| v.ptr as *const CIrValue).collect();
227        let result = xlsynth_sys::xls_value_make_tuple(elements_ptrs.len(), elements_ptrs.as_ptr());
228        assert!(!result.is_null());
229        IrValue { ptr: result }
230    }
231}
232
233pub(crate) fn xls_value_make_array(elements: &[IrValue]) -> Result<IrValue, XlsynthError> {
234    let elements_ptrs: Vec<*const CIrValue> =
235        elements.iter().map(|v| v.ptr as *const CIrValue).collect();
236    let mut result: *mut CIrValue = std::ptr::null_mut();
237    xls_ffi_call!(xlsynth_sys::xls_value_make_array, elements_ptrs.len(), elements_ptrs.as_ptr(); result)?;
238    Ok(IrValue { ptr: result })
239}
240
241pub(crate) fn xls_bits_to_debug_str(p: *const CIrBits) -> String {
242    unsafe {
243        let c_str_out = xlsynth_sys::xls_bits_to_debug_string(p);
244        c_str_to_rust(c_str_out)
245    }
246}
247
248pub(crate) fn xls_bits_make_ubits(bit_count: usize, value: u64) -> Result<IrBits, XlsynthError> {
249    let mut result: *mut CIrBits = std::ptr::null_mut();
250    xls_ffi_call!(xlsynth_sys::xls_bits_make_ubits, bit_count as i64, value; result)?;
251    Ok(IrBits { ptr: result })
252}
253
254pub(crate) fn xls_bits_make_sbits(bit_count: usize, value: i64) -> Result<IrBits, XlsynthError> {
255    let mut result: *mut CIrBits = std::ptr::null_mut();
256    xls_ffi_call!(xlsynth_sys::xls_bits_make_sbits, bit_count as i64, value; result)?;
257    Ok(IrBits { ptr: result })
258}
259
260pub(crate) fn xls_value_get_bits(p: *const CIrValue) -> Result<IrBits, XlsynthError> {
261    let mut result: *mut CIrBits = std::ptr::null_mut();
262    xls_ffi_call!(xlsynth_sys::xls_value_get_bits, p; result)?;
263    Ok(IrBits { ptr: result })
264}
265
266pub(crate) fn xls_format_preference_from_string(
267    s: &str,
268) -> Result<XlsFormatPreference, XlsynthError> {
269    let c_str = CString::new(s).unwrap();
270    let mut result_out: XlsFormatPreference = -1;
271    xls_ffi_call!(xlsynth_sys::xls_format_preference_from_string, c_str.as_ptr(); result_out)?;
272    Ok(result_out)
273}
274
275pub(crate) fn xls_value_to_string_format_preference(
276    p: *mut CIrValue,
277    fmt: XlsFormatPreference,
278) -> Result<String, XlsynthError> {
279    let mut c_str_out: *mut std::os::raw::c_char = std::ptr::null_mut();
280    xls_ffi_call!(xlsynth_sys::xls_value_to_string_format_preference, p, fmt; c_str_out)?;
281    Ok(unsafe { c_str_to_rust(c_str_out) })
282}
283
284pub(crate) fn xls_bits_to_string(
285    p: *const CIrBits,
286    fmt: XlsFormatPreference,
287    include_bit_count: bool,
288) -> Result<String, XlsynthError> {
289    let mut c_str_out: *mut std::os::raw::c_char = std::ptr::null_mut();
290    xls_ffi_call!(xlsynth_sys::xls_bits_to_string, p, fmt, include_bit_count; c_str_out)?;
291    Ok(unsafe { c_str_to_rust(c_str_out) })
292}
293
294pub(crate) fn xls_bits_to_bytes(p: *const CIrBits) -> Result<Vec<u8>, XlsynthError> {
295    unsafe {
296        let mut error_out: *mut std::os::raw::c_char = std::ptr::null_mut();
297        let mut bytes_out: *mut u8 = std::ptr::null_mut();
298        let mut byte_count_out: usize = 0;
299        let success =
300            xlsynth_sys::xls_bits_to_bytes(p, &mut error_out, &mut bytes_out, &mut byte_count_out);
301        if !success {
302            return Err(XlsynthError(c_str_to_rust(error_out)));
303        }
304        let slice = std::slice::from_raw_parts(bytes_out, byte_count_out);
305        let vec = slice.to_vec();
306        xlsynth_sys::xls_bytes_free(bytes_out);
307        Ok(vec)
308    }
309}
310
311pub(crate) fn xls_bits_to_uint64(p: *const CIrBits) -> Result<u64, XlsynthError> {
312    let mut value_out: u64 = 0;
313    xls_ffi_call!(xlsynth_sys::xls_bits_to_uint64, p; value_out)?;
314    Ok(value_out)
315}
316
317pub(crate) fn xls_bits_to_int64(p: *const CIrBits) -> Result<i64, XlsynthError> {
318    let mut value_out: i64 = 0;
319    xls_ffi_call!(xlsynth_sys::xls_bits_to_int64, p; value_out)?;
320    Ok(value_out)
321}
322
323pub(crate) fn xls_value_eq(
324    lhs: *const CIrValue,
325    rhs: *const CIrValue,
326) -> Result<bool, XlsynthError> {
327    unsafe { Ok(xlsynth_sys::xls_value_eq(lhs, rhs)) }
328}
329
330pub(crate) fn xls_parse_ir_package(
331    ir: &str,
332    filename: Option<&str>,
333) -> Result<crate::ir_package::IrPackage, XlsynthError> {
334    let ir_cstring = CString::new(ir).unwrap();
335    let (_filename_cstr, filename_ptr) = optional_cstring_and_ptr(filename);
336    let mut xls_package_out: *mut CIrPackage = std::ptr::null_mut();
337    xls_ffi_call!(xlsynth_sys::xls_parse_ir_package, ir_cstring.as_ptr(), filename_ptr; xls_package_out)?;
338    let package = crate::ir_package::IrPackage {
339        ptr: Arc::new(RwLock::new(IrPackagePtr(xls_package_out))),
340        filename: filename.map(|s| s.to_string()),
341    };
342    Ok(package)
343}
344
345pub(crate) fn xls_ir_analysis_create_from_package_with_options(
346    p: *mut CIrPackage,
347    options: Option<&xlsynth_sys::XlsIrAnalysisOptions>,
348) -> Result<*mut CIrAnalysis, XlsynthError> {
349    let mut out: *mut CIrAnalysis = std::ptr::null_mut();
350    let options_ptr: *const xlsynth_sys::XlsIrAnalysisOptions = options
351        .map_or(std::ptr::null(), |o| {
352            o as *const xlsynth_sys::XlsIrAnalysisOptions
353        });
354    xls_ffi_call!(
355        xlsynth_sys::xls_ir_analysis_create_from_package_with_options,
356        p,
357        options_ptr;
358        out
359    )?;
360    Ok(out)
361}
362
363pub(crate) fn xls_ir_analysis_get_known_bits_for_node_id(
364    a: *const CIrAnalysis,
365    node_id: i64,
366) -> Result<(IrBits, IrBits), XlsynthError> {
367    unsafe {
368        let mut error_out: *mut std::os::raw::c_char = std::ptr::null_mut();
369        let mut known_mask_out: *mut CIrBits = std::ptr::null_mut();
370        let mut known_value_out: *mut CIrBits = std::ptr::null_mut();
371        let success = xlsynth_sys::xls_ir_analysis_get_known_bits_for_node_id(
372            a,
373            node_id,
374            &mut error_out,
375            &mut known_mask_out,
376            &mut known_value_out,
377        );
378        if success {
379            Ok((
380                IrBits {
381                    ptr: known_mask_out,
382                },
383                IrBits {
384                    ptr: known_value_out,
385                },
386            ))
387        } else {
388            Err(XlsynthError(c_str_to_rust(error_out)))
389        }
390    }
391}
392
393pub(crate) fn xls_ir_analysis_get_intervals_for_node_id(
394    a: *const CIrAnalysis,
395    node_id: i64,
396) -> Result<*mut CIrIntervalSet, XlsynthError> {
397    let mut intervals_out: *mut CIrIntervalSet = std::ptr::null_mut();
398    xls_ffi_call!(
399        xlsynth_sys::xls_ir_analysis_get_intervals_for_node_id,
400        a,
401        node_id;
402        intervals_out
403    )?;
404    Ok(intervals_out)
405}
406
407pub(crate) fn xls_interval_set_get_interval_bounds(
408    s: *const CIrIntervalSet,
409    i: i64,
410) -> Result<(IrBits, IrBits), XlsynthError> {
411    unsafe {
412        let mut error_out: *mut std::os::raw::c_char = std::ptr::null_mut();
413        let mut lo_out: *mut CIrBits = std::ptr::null_mut();
414        let mut hi_out: *mut CIrBits = std::ptr::null_mut();
415        let success = xlsynth_sys::xls_interval_set_get_interval_bounds(
416            s,
417            i,
418            &mut error_out,
419            &mut lo_out,
420            &mut hi_out,
421        );
422        if success {
423            Ok((IrBits { ptr: lo_out }, IrBits { ptr: hi_out }))
424        } else {
425            Err(XlsynthError(c_str_to_rust(error_out)))
426        }
427    }
428}
429
430pub(crate) fn xls_package_new(name: &str) -> Result<crate::ir_package::IrPackage, XlsynthError> {
431    let (_name_cstr, name_ptr) = cstring_and_ptr(name);
432    let xls_package_out: *mut CIrPackage = unsafe { xlsynth_sys::xls_package_create(name_ptr) };
433    Ok(crate::ir_package::IrPackage {
434        ptr: Arc::new(RwLock::new(IrPackagePtr(xls_package_out))),
435        filename: None,
436    })
437}
438
439pub(crate) fn xls_function_builder_new(
440    package: *mut CIrPackage,
441    name: &str,
442    should_verify: bool,
443) -> Arc<RwLock<IrFnBuilderPtr>> {
444    let (_name_cstr, name_ptr) = cstring_and_ptr(name);
445    let fn_builder =
446        unsafe { xlsynth_sys::xls_function_builder_create(name_ptr, package, should_verify) };
447    assert!(!fn_builder.is_null());
448    Arc::new(RwLock::new(IrFnBuilderPtr { ptr: fn_builder }))
449}
450
451pub(crate) fn xls_function_builder_add_parameter(
452    builder: RwLockWriteGuard<IrFnBuilderPtr>,
453    name: &str,
454    type_: &IrType,
455) -> Arc<RwLock<BValuePtr>> {
456    let (_name_cstr, name_ptr) = cstring_and_ptr(name);
457    let type_raw = type_.ptr;
458    let bvalue_raw =
459        unsafe { xlsynth_sys::xls_function_builder_add_parameter(builder.ptr, name_ptr, type_raw) };
460    Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw }))
461}
462
463pub(crate) fn xls_function_builder_add_dynamic_bit_slice(
464    builder: RwLockWriteGuard<IrFnBuilderPtr>,
465    value: RwLockReadGuard<BValuePtr>,
466    start: RwLockReadGuard<BValuePtr>,
467    width: u64,
468    name: Option<&str>,
469) -> Arc<RwLock<BValuePtr>> {
470    let (_name_cstr, name_ptr) = optional_cstring_and_ptr(name);
471    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
472    let width_i64 = width as i64;
473    let bvalue_raw = unsafe {
474        xlsynth_sys::xls_builder_base_add_dynamic_bit_slice(
475            builder_base,
476            value.ptr,
477            start.ptr,
478            width_i64,
479            name_ptr,
480        )
481    };
482    Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw }))
483}
484
485pub(crate) fn xls_function_builder_add_bit_slice(
486    builder: RwLockWriteGuard<IrFnBuilderPtr>,
487    value: RwLockReadGuard<BValuePtr>,
488    start: u64,
489    width: u64,
490    name: Option<&str>,
491) -> Arc<RwLock<BValuePtr>> {
492    let (_name_cstr, name_ptr) = optional_cstring_and_ptr(name);
493    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
494    let bvalue_raw = unsafe {
495        xlsynth_sys::xls_builder_base_add_bit_slice(
496            builder_base,
497            value.ptr,
498            start as i64,
499            width as i64,
500            name_ptr,
501        )
502    };
503    Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw }))
504}
505
506pub(crate) fn xls_function_builder_add_concat(
507    builder: RwLockWriteGuard<IrFnBuilderPtr>,
508    values: &[RwLockReadGuard<BValuePtr>],
509    name: Option<&str>,
510) -> Arc<RwLock<BValuePtr>> {
511    let (_name_cstr, name_ptr) = optional_cstring_and_ptr(name);
512    let values_ptrs: Vec<*mut CIrBValue> = values.iter().map(|v| v.ptr).collect();
513    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
514    let bvalue_raw = unsafe {
515        xlsynth_sys::xls_builder_base_add_concat(
516            builder_base,
517            values_ptrs.as_ptr(),
518            values.len() as i64,
519            name_ptr,
520        )
521    };
522    Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw }))
523}
524
525pub(crate) fn xls_function_builder_add_literal(
526    builder: RwLockWriteGuard<IrFnBuilderPtr>,
527    value: &IrValue,
528    name: Option<&str>,
529) -> Arc<RwLock<BValuePtr>> {
530    let (_name_cstr, name_ptr) = optional_cstring_and_ptr(name);
531    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
532    let bvalue_raw =
533        unsafe { xlsynth_sys::xls_builder_base_add_literal(builder_base, value.ptr, name_ptr) };
534    Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw }))
535}
536
537pub(crate) fn xls_function_builder_add_tuple(
538    builder: RwLockWriteGuard<IrFnBuilderPtr>,
539    elements: &[RwLockReadGuard<BValuePtr>],
540    name: Option<&str>,
541) -> Arc<RwLock<BValuePtr>> {
542    let (_name_cstr, name_ptr) = optional_cstring_and_ptr(name);
543    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
544    let mut elements_ptrs: Vec<*mut CIrBValue> = elements.iter().map(|v| v.ptr).collect();
545    let bvalue_raw = unsafe {
546        xlsynth_sys::xls_builder_base_add_tuple(
547            builder_base,
548            elements_ptrs.as_mut_ptr(),
549            elements.len() as i64,
550            name_ptr,
551        )
552    };
553    Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw }))
554}
555
556pub(crate) fn xls_function_builder_add_tuple_index(
557    builder: RwLockWriteGuard<IrFnBuilderPtr>,
558    tuple: RwLockReadGuard<BValuePtr>,
559    index: u64,
560    name: Option<&str>,
561) -> Arc<RwLock<BValuePtr>> {
562    let (_name_cstr, name_ptr) = optional_cstring_and_ptr(name);
563    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
564    let bvalue_raw = unsafe {
565        xlsynth_sys::xls_builder_base_add_tuple_index(
566            builder_base,
567            tuple.ptr,
568            index as i64,
569            name_ptr,
570        )
571    };
572    Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw }))
573}
574
575pub(crate) fn xls_function_builder_build_with_return_value(
576    package: &Arc<RwLock<IrPackagePtr>>,
577    _package_guard: RwLockWriteGuard<IrPackagePtr>,
578    builder: RwLockWriteGuard<IrFnBuilderPtr>,
579    return_value: RwLockReadGuard<BValuePtr>,
580) -> Result<IrFunction, XlsynthError> {
581    let return_value_ptr = return_value.ptr;
582    let mut result_out: *mut CIrFunction = std::ptr::null_mut();
583    xls_ffi_call!(xlsynth_sys::xls_function_builder_build_with_return_value, builder.ptr, return_value_ptr; result_out)?;
584    Ok(IrFunction {
585        parent: package.clone(),
586        ptr: result_out,
587    })
588}
589
590pub(crate) fn xls_type_to_string(t: *const CIrType) -> Result<String, XlsynthError> {
591    let mut c_str_out: *mut std::os::raw::c_char = std::ptr::null_mut();
592    xls_ffi_call!(xlsynth_sys::xls_type_to_string, t; c_str_out)?;
593    Ok(unsafe { c_str_to_rust(c_str_out) })
594}
595
596pub(crate) fn xls_type_get_flat_bit_count(t: *const CIrType) -> u64 {
597    let bit_count = unsafe { xlsynth_sys::xls_type_get_flat_bit_count(t) };
598    assert!(bit_count >= 0, "bit count must be non-negative");
599    bit_count as u64
600}
601
602pub(crate) fn xls_package_set_top_by_name(
603    package: *mut CIrPackage,
604    name: &str,
605) -> Result<(), XlsynthError> {
606    let (_name_cstr, name_ptr) = cstring_and_ptr(name);
607    xls_ffi_call_noreturn!(xlsynth_sys::xls_package_set_top_by_name, package, name_ptr)?;
608    Ok(())
609}
610
611pub(crate) fn xls_verify_package(package: *mut CIrPackage) -> Result<(), XlsynthError> {
612    xls_ffi_call_noreturn!(xlsynth_sys::xls_verify_package, package)?;
613    Ok(())
614}
615
616pub(crate) fn xls_package_get_bits_type(package: *mut CIrPackage, bit_count: u64) -> *mut CIrType {
617    unsafe { xlsynth_sys::xls_package_get_bits_type(package, bit_count as i64) }
618}
619
620pub(crate) fn xls_package_get_tuple_type(
621    package: *mut CIrPackage,
622    members: &[IrType],
623) -> *mut CIrType {
624    let mut members_ptrs: Vec<*mut CIrType> = members.iter().map(|v| v.ptr).collect();
625    let members_ptr = members_ptrs.as_mut_ptr();
626    let member_count = members_ptrs.len() as i64;
627    unsafe { xlsynth_sys::xls_package_get_tuple_type(package, members_ptr, member_count) }
628}
629
630pub(crate) fn xls_package_get_array_type(
631    package: *mut CIrPackage,
632    element_type: *mut CIrType,
633    size: i64,
634) -> *mut CIrType {
635    unsafe { xlsynth_sys::xls_package_get_array_type(package, element_type, size) }
636}
637
638pub(crate) fn xls_package_get_token_type(package: *mut CIrPackage) -> *mut CIrType {
639    unsafe { xlsynth_sys::xls_package_get_token_type(package) }
640}
641
642pub(crate) fn xls_package_get_type_for_value(
643    package: *mut CIrPackage,
644    value: *mut CIrValue,
645) -> Result<*mut CIrType, XlsynthError> {
646    let mut result_out: *mut CIrType = std::ptr::null_mut();
647    xls_ffi_call!(xlsynth_sys::xls_package_get_type_for_value, package, value; result_out)?;
648    Ok(result_out)
649}
650
651pub(crate) fn xls_package_get_function(
652    package: &Arc<RwLock<IrPackagePtr>>,
653    guard: RwLockReadGuard<IrPackagePtr>,
654    function_name: &str,
655) -> Result<crate::ir_package::IrFunction, XlsynthError> {
656    let function_name = CString::new(function_name).unwrap();
657    let mut result_out: *mut CIrFunction = std::ptr::null_mut();
658    xls_ffi_call!(xlsynth_sys::xls_package_get_function, guard.const_c_ptr(), function_name.as_ptr(); result_out)?;
659    Ok(crate::ir_package::IrFunction {
660        parent: package.clone(),
661        ptr: result_out,
662    })
663}
664
665pub(crate) fn xls_package_get_functions(
666    package: &Arc<RwLock<IrPackagePtr>>,
667    guard: RwLockWriteGuard<IrPackagePtr>,
668) -> Result<Vec<crate::ir_package::IrFunction>, XlsynthError> {
669    unsafe {
670        let mut error_out: *mut std::os::raw::c_char = std::ptr::null_mut();
671        let mut result_out: *mut *mut CIrFunction = std::ptr::null_mut();
672        let mut count_out: libc::size_t = 0;
673        let success = xlsynth_sys::xls_package_get_functions(
674            guard.mut_c_ptr(),
675            &mut error_out,
676            &mut result_out,
677            &mut count_out,
678        );
679        if !success {
680            return Err(XlsynthError(c_str_to_rust(error_out)));
681        }
682
683        let functions = if result_out.is_null() || count_out == 0 {
684            Vec::new()
685        } else {
686            let raw_slice = std::slice::from_raw_parts(result_out, count_out);
687            raw_slice
688                .iter()
689                .map(|&ptr| crate::ir_package::IrFunction {
690                    parent: package.clone(),
691                    ptr,
692                })
693                .collect()
694        };
695
696        if !result_out.is_null() {
697            xlsynth_sys::xls_function_ptr_array_free(result_out);
698        }
699
700        Ok(functions)
701    }
702}
703
704pub(crate) fn xls_function_get_type(
705    _package_write_guard: &RwLockWriteGuard<IrPackagePtr>,
706    function: *const CIrFunction,
707) -> Result<*mut CIrFunctionType, XlsynthError> {
708    let mut xls_fn_type_out: *mut CIrFunctionType = std::ptr::null_mut();
709    xls_ffi_call!(xlsynth_sys::xls_function_get_type, function; xls_fn_type_out)?;
710    Ok(xls_fn_type_out)
711}
712
713pub(crate) fn xls_function_type_to_string(
714    t: *const CIrFunctionType,
715) -> Result<String, XlsynthError> {
716    let mut c_str_out: *mut std::os::raw::c_char = std::ptr::null_mut();
717    xls_ffi_call!(xlsynth_sys::xls_function_type_to_string, t; c_str_out)?;
718    Ok(unsafe { c_str_to_rust(c_str_out) })
719}
720
721pub(crate) fn xls_function_get_name(function: *const CIrFunction) -> Result<String, XlsynthError> {
722    let mut c_str_out: *mut std::os::raw::c_char = std::ptr::null_mut();
723    xls_ffi_call!(xlsynth_sys::xls_function_get_name, function; c_str_out)?;
724    Ok(unsafe { c_str_to_rust(c_str_out) })
725}
726
727pub(crate) fn xls_interpret_function(
728    _package_guard: &RwLockReadGuard<IrPackagePtr>,
729    function: *const CIrFunction,
730    args: &[IrValue],
731) -> Result<IrValue, XlsynthError> {
732    let args_ptrs: Vec<*const CIrValue> =
733        args.iter().map(|v| -> *const CIrValue { v.ptr }).collect();
734    let argc = args_ptrs.len();
735    let mut result_out: *mut CIrValue = std::ptr::null_mut();
736    xls_ffi_call!(xlsynth_sys::xls_interpret_function, function, argc, args_ptrs.as_ptr(); result_out)?;
737    Ok(IrValue { ptr: result_out })
738}
739
740pub(crate) fn xls_optimize_ir(ir: &str, top: &str) -> Result<String, XlsynthError> {
741    let ir = CString::new(ir).unwrap();
742    let top = CString::new(top).unwrap();
743    let mut ir_out: *mut std::os::raw::c_char = std::ptr::null_mut();
744    xls_ffi_call!(xlsynth_sys::xls_optimize_ir, ir.as_ptr(), top.as_ptr(); ir_out)?;
745    let ir_str = unsafe { c_str_to_rust(ir_out) };
746    Ok(ir_str)
747}
748
749#[derive(Debug, Clone, PartialEq, Eq)]
750pub struct TraceMessage {
751    pub message: String,
752    pub verbosity: i64,
753}
754
755#[derive(Debug, Clone, PartialEq, Eq)]
756pub struct RunResult {
757    pub value: IrValue,
758    pub trace_messages: Vec<TraceMessage>,
759    pub assert_messages: Vec<String>,
760}
761
762// Helper that converts the trace messages to Rust objects and deallocates the C
763// value.
764unsafe fn trace_messages_to_rust(
765    c_trace_messages: *mut CTraceMessage,
766    count: usize,
767) -> Vec<TraceMessage> {
768    if c_trace_messages.is_null() {
769        return Vec::new();
770    }
771    let mut trace_messages: Vec<TraceMessage> = Vec::new();
772    for i in 0..count {
773        let trace_message: &CTraceMessage = unsafe { &*c_trace_messages.wrapping_add(i) };
774        trace_messages.push(TraceMessage {
775            message: unsafe { c_str_to_rust_no_dealloc(trace_message.message) },
776            verbosity: trace_message.verbosity,
777        });
778    }
779    xlsynth_sys::xls_trace_messages_free(c_trace_messages, count);
780    trace_messages
781}
782
783pub(crate) unsafe fn c_strs_to_rust(
784    c_strs: *mut *mut std::os::raw::c_char,
785    count: usize,
786) -> Vec<String> {
787    let mut result: Vec<String> = Vec::new();
788    for i in 0..count {
789        let xls_c_str: *mut std::os::raw::c_char = unsafe { *c_strs.wrapping_add(i) };
790        result.push(c_str_to_rust_no_dealloc(xls_c_str));
791    }
792    if !c_strs.is_null() && count > 0 {
793        unsafe {
794            xlsynth_sys::xls_c_strs_free(c_strs, count);
795        }
796    }
797    result
798}
799
800pub(crate) fn xls_make_function_jit(
801    _package_guard: &RwLockReadGuard<IrPackagePtr>,
802    function: *const CIrFunction,
803) -> Result<*mut CIrFunctionJit, XlsynthError> {
804    let mut ptr: *mut CIrFunctionJit = std::ptr::null_mut();
805    xls_ffi_call!(xlsynth_sys::xls_make_function_jit, function; ptr)?;
806    Ok(ptr)
807}
808
809pub(crate) fn xls_function_jit_run(
810    _package_guard: &RwLockReadGuard<IrPackagePtr>,
811    jit: *const CIrFunctionJit,
812    args: &[IrValue],
813) -> Result<RunResult, XlsynthError> {
814    let mut result_out: *mut CIrValue = std::ptr::null_mut();
815    let mut error_out: *mut std::os::raw::c_char = std::ptr::null_mut();
816    let argc = args.len();
817    let args_ptrs: Vec<*const CIrValue> =
818        args.iter().map(|v| -> *const CIrValue { v.ptr }).collect();
819    let mut trace_messages_out: *mut CTraceMessage = std::ptr::null_mut();
820    let mut trace_messages_count: usize = 0;
821    let mut assert_messages_out: *mut *mut std::os::raw::c_char = std::ptr::null_mut();
822    let mut assert_messages_count: usize = 0;
823    let success = unsafe {
824        xlsynth_sys::xls_function_jit_run(
825            jit,
826            argc,
827            args_ptrs.as_ptr(),
828            &mut error_out,
829            &mut trace_messages_out,
830            &mut trace_messages_count,
831            &mut assert_messages_out,
832            &mut assert_messages_count,
833            &mut result_out,
834        )
835    };
836    if !success {
837        let error_message = unsafe { c_str_to_rust(error_out) };
838        return Err(XlsynthError(format!(
839            "Failed to run JIT function: {error_message}"
840        )));
841    }
842    let trace_messages =
843        unsafe { trace_messages_to_rust(trace_messages_out, trace_messages_count) };
844    let assert_messages = unsafe { c_strs_to_rust(assert_messages_out, assert_messages_count) };
845    Ok(RunResult {
846        value: IrValue { ptr: result_out },
847        trace_messages,
848        assert_messages,
849    })
850}
851
852pub(crate) fn xls_mangle_dslx_name(
853    module_name: &str,
854    function_name: &str,
855) -> Result<String, XlsynthError> {
856    let module_name = CString::new(module_name).unwrap();
857    let function_name = CString::new(function_name).unwrap();
858    let mut mangled_out: *mut std::os::raw::c_char = std::ptr::null_mut();
859    xls_ffi_call!(xlsynth_sys::xls_mangle_dslx_name, module_name.as_ptr(), function_name.as_ptr(); mangled_out)?;
860    Ok(unsafe { c_str_to_rust(mangled_out) })
861}
862
863pub(crate) fn xls_mangle_dslx_name_full(
864    module_name: &str,
865    function_name: &str,
866    convention: crate::DslxCallingConvention,
867    free_keys: &[&str],
868    param_env: Option<&crate::dslx::ParametricEnv>,
869    scope: Option<&str>,
870) -> Result<String, XlsynthError> {
871    let module_c = std::ffi::CString::new(module_name).unwrap();
872    let function_c = std::ffi::CString::new(function_name).unwrap();
873
874    let free_key_cstrs: Vec<std::ffi::CString> = free_keys
875        .iter()
876        .map(|s| std::ffi::CString::new((*s).as_bytes()).unwrap())
877        .collect();
878    let free_key_ptrs: Vec<*const std::os::raw::c_char> =
879        free_key_cstrs.iter().map(|s| s.as_ptr()).collect();
880    let free_keys_ptr = if free_key_ptrs.is_empty() {
881        std::ptr::null()
882    } else {
883        free_key_ptrs.as_ptr()
884    };
885
886    let (_scope_cstr_opt, scope_ptr) = optional_cstring_and_ptr(scope);
887    let cc: xlsynth_sys::XlsCallingConvention = convention.into();
888
889    let mut mangled_out: *mut std::os::raw::c_char = std::ptr::null_mut();
890    xls_ffi_call!(
891        xlsynth_sys::xls_mangle_dslx_name_full,
892        module_c.as_ptr(),
893        function_c.as_ptr(),
894        cc,
895        free_keys_ptr,
896        free_key_ptrs.len(),
897        param_env.map(|e| e.ptr as *const _).unwrap_or(std::ptr::null()),
898        scope_ptr;
899        mangled_out
900    )?;
901    Ok(unsafe { c_str_to_rust(mangled_out) })
902}
903
904pub(crate) fn xls_schedule_and_codegen_package(
905    _package: &Arc<RwLock<IrPackagePtr>>,
906    guard: RwLockWriteGuard<IrPackagePtr>,
907    scheduling_options_flags_proto_str: &str,
908    codegen_flags_proto_str: &str,
909    with_delay_model: bool,
910) -> Result<ScheduleAndCodegenResult, XlsynthError> {
911    let scheduling_options_flags_proto = CString::new(scheduling_options_flags_proto_str).unwrap();
912    let codegen_flags_proto = CString::new(codegen_flags_proto_str).unwrap();
913    let mut result_out: *mut CScheduleAndCodegenResult = std::ptr::null_mut();
914    xls_ffi_call!(xlsynth_sys::xls_schedule_and_codegen_package,
915        guard.mut_c_ptr(),
916        scheduling_options_flags_proto.as_ptr(),
917        codegen_flags_proto.as_ptr(),
918        with_delay_model;
919        result_out
920    )?;
921    assert!(!result_out.is_null());
922    Ok(ScheduleAndCodegenResult { ptr: result_out })
923}
924
925pub(crate) fn xls_function_builder_add_array(
926    builder: RwLockWriteGuard<IrFnBuilderPtr>,
927    element_type: &IrType,
928    elements: &[RwLockReadGuard<BValuePtr>],
929    name: Option<&str>,
930) -> Arc<RwLock<BValuePtr>> {
931    let (_name_cstr, name_ptr) = optional_cstring_and_ptr(name);
932    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
933    let elements_ptrs: Vec<*mut CIrBValue> = elements.iter().map(|v| v.ptr).collect();
934    let bvalue_raw = unsafe {
935        xlsynth_sys::xls_builder_base_add_array(
936            builder_base,
937            element_type.ptr,
938            elements_ptrs.as_ptr(),
939            elements_ptrs.len() as i64,
940            name_ptr,
941        )
942    };
943    Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw }))
944}
945
946pub(crate) fn xls_function_builder_add_array_index_multi(
947    builder: RwLockWriteGuard<IrFnBuilderPtr>,
948    array: RwLockReadGuard<BValuePtr>,
949    index: &[RwLockReadGuard<BValuePtr>],
950    assumed_in_bounds: bool,
951    name: Option<&str>,
952) -> Arc<RwLock<BValuePtr>> {
953    let (_name_cstr, name_ptr) = optional_cstring_and_ptr(name);
954    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
955    let index_ptrs: Vec<*mut CIrBValue> = index.iter().map(|v| v.ptr).collect();
956    let bvalue_raw = unsafe {
957        xlsynth_sys::xls_builder_base_add_array_index(
958            builder_base,
959            array.ptr,
960            index_ptrs.as_ptr(),
961            index_ptrs.len() as i64,
962            assumed_in_bounds,
963            name_ptr,
964        )
965    };
966    Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw }))
967}
968
969pub(crate) fn xls_function_builder_add_bit_slice_update(
970    builder: RwLockWriteGuard<IrFnBuilderPtr>,
971    value: RwLockReadGuard<BValuePtr>,
972    start: RwLockReadGuard<BValuePtr>,
973    update: RwLockReadGuard<BValuePtr>,
974    name: Option<&str>,
975) -> Arc<RwLock<BValuePtr>> {
976    let (_name_cstr, name_ptr) = optional_cstring_and_ptr(name);
977    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
978    let bvalue_raw = unsafe {
979        xlsynth_sys::xls_builder_base_add_bit_slice_update(
980            builder_base,
981            value.ptr,
982            start.ptr,
983            update.ptr,
984            name_ptr,
985        )
986    };
987    Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw }))
988}
989
990pub(crate) fn xls_function_builder_add_select(
991    builder: RwLockWriteGuard<IrFnBuilderPtr>,
992    selector: RwLockReadGuard<BValuePtr>,
993    cases: &[RwLockReadGuard<BValuePtr>],
994    default_value: RwLockReadGuard<BValuePtr>,
995    name: Option<&str>,
996) -> Arc<RwLock<BValuePtr>> {
997    let (_name_cstr, name_ptr) = optional_cstring_and_ptr(name);
998    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
999    let cases_ptrs: Vec<*mut CIrBValue> = cases.iter().map(|v| v.ptr).collect();
1000    let bvalue_raw = unsafe {
1001        xlsynth_sys::xls_builder_base_add_select(
1002            builder_base,
1003            selector.ptr,
1004            cases_ptrs.as_ptr(),
1005            cases_ptrs.len() as i64,
1006            default_value.ptr,
1007            name_ptr,
1008        )
1009    };
1010    Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw }))
1011}
1012
1013pub(crate) fn xls_function_builder_add_array_concat(
1014    builder: RwLockWriteGuard<IrFnBuilderPtr>,
1015    arrays: &[RwLockReadGuard<BValuePtr>],
1016    name: Option<&str>,
1017) -> Arc<RwLock<BValuePtr>> {
1018    let (_name_cstr, name_ptr) = optional_cstring_and_ptr(name);
1019    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
1020    let arrays_ptrs: Vec<*mut CIrBValue> = arrays.iter().map(|v| v.ptr).collect();
1021    let bvalue_raw = unsafe {
1022        xlsynth_sys::xls_builder_base_add_array_concat(
1023            builder_base,
1024            arrays_ptrs.as_ptr(),
1025            arrays_ptrs.len() as i64,
1026            name_ptr,
1027        )
1028    };
1029    Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw }))
1030}
1031
1032pub(crate) fn xls_function_builder_add_array_slice(
1033    builder: RwLockWriteGuard<IrFnBuilderPtr>,
1034    array: RwLockReadGuard<BValuePtr>,
1035    start: RwLockReadGuard<BValuePtr>,
1036    width: i64,
1037    name: Option<&str>,
1038) -> Arc<RwLock<BValuePtr>> {
1039    let (_name_cstr, name_ptr) = optional_cstring_and_ptr(name);
1040    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
1041    let bvalue_raw = unsafe {
1042        xlsynth_sys::xls_builder_base_add_array_slice(
1043            builder_base,
1044            array.ptr,
1045            start.ptr,
1046            width,
1047            name_ptr,
1048        )
1049    };
1050    Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw }))
1051}
1052
1053pub(crate) fn xls_function_builder_add_array_update(
1054    builder: RwLockWriteGuard<IrFnBuilderPtr>,
1055    array: RwLockReadGuard<BValuePtr>,
1056    update_value: RwLockReadGuard<BValuePtr>,
1057    indices: &[RwLockReadGuard<BValuePtr>],
1058    assumed_in_bounds: bool,
1059    name: Option<&str>,
1060) -> Arc<RwLock<BValuePtr>> {
1061    let (_name_cstr, name_ptr) = optional_cstring_and_ptr(name);
1062    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
1063    let indices_ptrs: Vec<*mut CIrBValue> = indices.iter().map(|v| v.ptr).collect();
1064    let bvalue_raw = unsafe {
1065        xlsynth_sys::xls_builder_base_add_array_update(
1066            builder_base,
1067            array.ptr,
1068            update_value.ptr,
1069            indices_ptrs.as_ptr(),
1070            indices_ptrs.len() as i64,
1071            assumed_in_bounds,
1072            name_ptr,
1073        )
1074    };
1075    Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw }))
1076}
1077
1078pub(crate) fn xls_function_builder_add_sign_extend(
1079    builder: RwLockWriteGuard<IrFnBuilderPtr>,
1080    value: RwLockReadGuard<BValuePtr>,
1081    new_bit_count: i64,
1082    name: Option<&str>,
1083) -> Arc<RwLock<BValuePtr>> {
1084    let name_cstr = name.map(|s| CString::new(s).unwrap());
1085    let name_ptr = name_cstr.as_ref().map_or(std::ptr::null(), |s| s.as_ptr());
1086    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
1087    let bvalue_raw = unsafe {
1088        xlsynth_sys::xls_builder_base_add_sign_extend(
1089            builder_base,
1090            value.ptr,
1091            new_bit_count,
1092            name_ptr,
1093        )
1094    };
1095    Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw }))
1096}
1097
1098pub(crate) fn xls_function_builder_add_zero_extend(
1099    builder: RwLockWriteGuard<IrFnBuilderPtr>,
1100    value: RwLockReadGuard<BValuePtr>,
1101    new_bit_count: i64,
1102    name: Option<&str>,
1103) -> Arc<RwLock<BValuePtr>> {
1104    let name_cstr = name.map(|s| CString::new(s).unwrap());
1105    let name_ptr = name_cstr.as_ref().map_or(std::ptr::null(), |s| s.as_ptr());
1106    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
1107    let bvalue_raw = unsafe {
1108        xlsynth_sys::xls_builder_base_add_zero_extend(
1109            builder_base,
1110            value.ptr,
1111            new_bit_count,
1112            name_ptr,
1113        )
1114    };
1115    Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw }))
1116}
1117
1118pub(crate) fn xls_function_builder_add_one_hot(
1119    builder: RwLockWriteGuard<IrFnBuilderPtr>,
1120    input: RwLockReadGuard<BValuePtr>,
1121    lsb_is_priority: bool,
1122    name: Option<&str>,
1123) -> Arc<RwLock<BValuePtr>> {
1124    let name_cstr = name.map(|s| CString::new(s).unwrap());
1125    let name_ptr = name_cstr.as_ref().map_or(std::ptr::null(), |s| s.as_ptr());
1126    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
1127    let bvalue_raw = unsafe {
1128        xlsynth_sys::xls_builder_base_add_one_hot(
1129            builder_base,
1130            input.ptr,
1131            lsb_is_priority,
1132            name_ptr,
1133        )
1134    };
1135    Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw }))
1136}
1137
1138pub(crate) fn xls_function_builder_add_priority_select(
1139    builder: RwLockWriteGuard<IrFnBuilderPtr>,
1140    selector: RwLockReadGuard<BValuePtr>,
1141    cases: &[RwLockReadGuard<BValuePtr>],
1142    default_value: RwLockReadGuard<BValuePtr>,
1143    name: Option<&str>,
1144) -> Arc<RwLock<BValuePtr>> {
1145    let name_cstr = name.map(|s| CString::new(s).unwrap());
1146    let name_ptr = name_cstr.as_ref().map_or(std::ptr::null(), |s| s.as_ptr());
1147    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
1148    let cases_ptrs: Vec<*mut CIrBValue> = cases.iter().map(|v| v.ptr).collect();
1149    let bvalue_raw = unsafe {
1150        xlsynth_sys::xls_builder_base_add_priority_select(
1151            builder_base,
1152            selector.ptr,
1153            cases_ptrs.as_ptr(),
1154            cases_ptrs.len() as i64,
1155            default_value.ptr,
1156            name_ptr,
1157        )
1158    };
1159    Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw }))
1160}
1161
1162pub(crate) fn xls_function_builder_add_one_hot_select(
1163    builder: RwLockWriteGuard<IrFnBuilderPtr>,
1164    selector: RwLockReadGuard<BValuePtr>,
1165    cases: &[RwLockReadGuard<BValuePtr>],
1166    name: Option<&str>,
1167) -> Arc<RwLock<BValuePtr>> {
1168    let name_cstr = name.map(|s| CString::new(s).unwrap());
1169    let name_ptr = name_cstr.as_ref().map_or(std::ptr::null(), |s| s.as_ptr());
1170    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
1171    let cases_ptrs: Vec<*mut CIrBValue> = cases.iter().map(|v| v.ptr).collect();
1172    let bvalue_raw = unsafe {
1173        xlsynth_sys::xls_builder_base_add_one_hot_select(
1174            builder_base,
1175            selector.ptr,
1176            cases_ptrs.as_ptr(),
1177            cases_ptrs.len() as i64,
1178            name_ptr,
1179        )
1180    };
1181    Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw }))
1182}
1183
1184pub(crate) fn xls_function_builder_add_decode(
1185    builder: RwLockWriteGuard<IrFnBuilderPtr>,
1186    value: RwLockReadGuard<BValuePtr>,
1187    width: Option<u64>,
1188    name: Option<&str>,
1189) -> Arc<RwLock<BValuePtr>> {
1190    let name_cstr = name.map(|s| CString::new(s).unwrap());
1191    let name_ptr = name_cstr.as_ref().map_or(std::ptr::null(), |s| s.as_ptr());
1192    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
1193
1194    let mut width_value = width.unwrap_or(0);
1195    let width_ptr: *mut i64 = if width.is_some() {
1196        &mut width_value as *mut u64 as *mut i64
1197    } else {
1198        std::ptr::null_mut()
1199    };
1200    let bvalue_raw = unsafe {
1201        xlsynth_sys::xls_builder_base_add_decode(builder_base, value.ptr, width_ptr, name_ptr)
1202    };
1203    Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw }))
1204}
1205
1206pub(crate) fn xls_function_builder_last_value(
1207    builder: RwLockReadGuard<IrFnBuilderPtr>,
1208) -> Result<Arc<RwLock<BValuePtr>>, XlsynthError> {
1209    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
1210    let mut bvalue_raw: *mut CIrBValue = std::ptr::null_mut();
1211    xls_ffi_call!(xlsynth_sys::xls_builder_base_get_last_value, builder_base; bvalue_raw)?;
1212    assert!(!bvalue_raw.is_null());
1213    Ok(Arc::new(RwLock::new(BValuePtr { ptr: bvalue_raw })))
1214}
1215
1216pub(crate) fn xls_function_builder_get_type(
1217    builder: RwLockReadGuard<IrFnBuilderPtr>,
1218    value: RwLockReadGuard<BValuePtr>,
1219) -> Option<*mut CIrType> {
1220    let builder_base = unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
1221    let type_raw = unsafe { xlsynth_sys::xls_builder_base_get_type(builder_base, value.ptr) };
1222    if type_raw.is_null() {
1223        None
1224    } else {
1225        Some(type_raw)
1226    }
1227}
1228
1229macro_rules! impl_binary_ir_builder {
1230    ($fn_name:ident, $ffi_func:ident) => {
1231        pub(crate) fn $fn_name(
1232            builder: std::sync::RwLockWriteGuard<IrFnBuilderPtr>,
1233            a: std::sync::RwLockReadGuard<BValuePtr>,
1234            b: std::sync::RwLockReadGuard<BValuePtr>,
1235            name: Option<&str>,
1236        ) -> std::sync::Arc<std::sync::RwLock<BValuePtr>> {
1237            let builder_base =
1238                unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
1239            let name_cstr = name.map(|s| std::ffi::CString::new(s).unwrap());
1240            let name_ptr = name_cstr.as_ref().map_or(std::ptr::null(), |s| s.as_ptr());
1241            let builder_base =
1242                unsafe { xlsynth_sys::$ffi_func(builder_base, a.ptr, b.ptr, name_ptr) };
1243            std::sync::Arc::new(std::sync::RwLock::new(BValuePtr { ptr: builder_base }))
1244        }
1245    };
1246}
1247
1248impl_binary_ir_builder!(xls_function_builder_add_add, xls_builder_base_add_add);
1249impl_binary_ir_builder!(xls_function_builder_add_sub, xls_builder_base_add_sub);
1250impl_binary_ir_builder!(xls_function_builder_add_shra, xls_builder_base_add_shra);
1251impl_binary_ir_builder!(xls_function_builder_add_shrl, xls_builder_base_add_shrl);
1252impl_binary_ir_builder!(xls_function_builder_add_shll, xls_builder_base_add_shll);
1253impl_binary_ir_builder!(xls_function_builder_add_nor, xls_builder_base_add_nor);
1254impl_binary_ir_builder!(xls_function_builder_add_and, xls_builder_base_add_and);
1255impl_binary_ir_builder!(xls_function_builder_add_nand, xls_builder_base_add_nand);
1256impl_binary_ir_builder!(xls_function_builder_add_or, xls_builder_base_add_or);
1257impl_binary_ir_builder!(xls_function_builder_add_xor, xls_builder_base_add_xor);
1258impl_binary_ir_builder!(xls_function_builder_add_eq, xls_builder_base_add_eq);
1259impl_binary_ir_builder!(xls_function_builder_add_ne, xls_builder_base_add_ne);
1260impl_binary_ir_builder!(xls_function_builder_add_ule, xls_builder_base_add_ule);
1261impl_binary_ir_builder!(xls_function_builder_add_ult, xls_builder_base_add_ult);
1262impl_binary_ir_builder!(xls_function_builder_add_uge, xls_builder_base_add_uge);
1263impl_binary_ir_builder!(xls_function_builder_add_ugt, xls_builder_base_add_ugt);
1264impl_binary_ir_builder!(xls_function_builder_add_sle, xls_builder_base_add_sle);
1265impl_binary_ir_builder!(xls_function_builder_add_slt, xls_builder_base_add_slt);
1266impl_binary_ir_builder!(xls_function_builder_add_sgt, xls_builder_base_add_sgt);
1267impl_binary_ir_builder!(xls_function_builder_add_sge, xls_builder_base_add_sge);
1268impl_binary_ir_builder!(xls_function_builder_add_umul, xls_builder_base_add_umul);
1269impl_binary_ir_builder!(xls_function_builder_add_smul, xls_builder_base_add_smul);
1270impl_binary_ir_builder!(xls_function_builder_add_udiv, xls_builder_base_add_udiv);
1271impl_binary_ir_builder!(xls_function_builder_add_sdiv, xls_builder_base_add_sdiv);
1272impl_binary_ir_builder!(xls_function_builder_add_umod, xls_builder_base_add_umod);
1273impl_binary_ir_builder!(xls_function_builder_add_smod, xls_builder_base_add_smod);
1274
1275macro_rules! impl_unary_ir_builder {
1276    ($fn_name:ident, $ffi_func:ident) => {
1277        pub(crate) fn $fn_name(
1278            builder: std::sync::RwLockWriteGuard<IrFnBuilderPtr>,
1279            a: std::sync::RwLockReadGuard<BValuePtr>,
1280            name: Option<&str>,
1281        ) -> std::sync::Arc<std::sync::RwLock<BValuePtr>> {
1282            let builder_base =
1283                unsafe { xlsynth_sys::xls_function_builder_as_builder_base(builder.ptr) };
1284            let name_cstr = name.map(|s| std::ffi::CString::new(s).unwrap());
1285            let name_ptr = name_cstr.as_ref().map_or(std::ptr::null(), |s| s.as_ptr());
1286            let builder_base = unsafe { xlsynth_sys::$ffi_func(builder_base, a.ptr, name_ptr) };
1287            std::sync::Arc::new(std::sync::RwLock::new(BValuePtr { ptr: builder_base }))
1288        }
1289    };
1290}
1291
1292impl_unary_ir_builder!(xls_function_builder_add_not, xls_builder_base_add_not);
1293impl_unary_ir_builder!(xls_function_builder_add_negate, xls_builder_base_add_negate);
1294impl_unary_ir_builder!(
1295    xls_function_builder_add_reverse,
1296    xls_builder_base_add_reverse
1297);
1298impl_unary_ir_builder!(
1299    xls_function_builder_add_or_reduce,
1300    xls_builder_base_add_or_reduce
1301);
1302impl_unary_ir_builder!(
1303    xls_function_builder_add_and_reduce,
1304    xls_builder_base_add_and_reduce
1305);
1306impl_unary_ir_builder!(
1307    xls_function_builder_add_xor_reduce,
1308    xls_builder_base_add_xor_reduce
1309);
1310impl_unary_ir_builder!(xls_function_builder_add_ctz, xls_builder_base_add_ctz);
1311impl_unary_ir_builder!(xls_function_builder_add_clz, xls_builder_base_add_clz);
1312impl_unary_ir_builder!(xls_function_builder_add_encode, xls_builder_base_add_encode);
1313impl_unary_ir_builder!(
1314    xls_function_builder_add_identity,
1315    xls_builder_base_add_identity
1316);
1317
1318pub(crate) fn xls_function_type_param_count(t: *mut xlsynth_sys::CIrFunctionType) -> i64 {
1319    unsafe { xlsynth_sys::xls_function_type_get_param_count(t) }
1320}
1321
1322pub(crate) fn xls_function_type_get_param_type(
1323    t: *mut xlsynth_sys::CIrFunctionType,
1324    index: usize,
1325) -> Result<*mut xlsynth_sys::CIrType, XlsynthError> {
1326    let mut error_out: *mut std::os::raw::c_char = std::ptr::null_mut();
1327    let mut type_out: *mut xlsynth_sys::CIrType = std::ptr::null_mut();
1328    let success = unsafe {
1329        xlsynth_sys::xls_function_type_get_param_type(t, index, &mut error_out, &mut type_out)
1330    };
1331    if success {
1332        Ok(type_out)
1333    } else {
1334        Err(XlsynthError(unsafe { c_str_to_rust(error_out) }))
1335    }
1336}
1337
1338pub(crate) fn xls_function_type_get_return_type(
1339    t: *mut xlsynth_sys::CIrFunctionType,
1340) -> *mut xlsynth_sys::CIrType {
1341    unsafe { xlsynth_sys::xls_function_type_get_return_type(t) }
1342}
1343
1344pub(crate) fn xls_function_get_param_name(
1345    f: *mut xlsynth_sys::CIrFunction,
1346    index: usize,
1347) -> Result<String, XlsynthError> {
1348    let mut error_out: *mut std::os::raw::c_char = std::ptr::null_mut();
1349    let mut name_out: *mut std::os::raw::c_char = std::ptr::null_mut();
1350    let success = unsafe {
1351        xlsynth_sys::xls_function_get_param_name(f, index, &mut error_out, &mut name_out)
1352    };
1353    if success {
1354        Ok(unsafe { c_str_to_rust(name_out) })
1355    } else {
1356        Err(XlsynthError(unsafe { c_str_to_rust(error_out) }))
1357    }
1358}