qir_stdlib/
bigints.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use crate::update_counts;
5use num_bigint::BigInt;
6use std::{mem::ManuallyDrop, rc::Rc};
7
8#[no_mangle]
9pub extern "C" fn __quantum__rt__bigint_create_i64(input: i64) -> *const BigInt {
10    Rc::into_raw(Rc::new(input.into()))
11}
12
13#[no_mangle]
14pub unsafe extern "C" fn __quantum__rt__bigint_create_array(
15    size: u32,
16    input: *const u8,
17) -> *const BigInt {
18    Rc::into_raw(Rc::new(BigInt::from_signed_bytes_le(
19        std::slice::from_raw_parts(input, size as usize),
20    )))
21}
22
23#[no_mangle]
24pub unsafe extern "C" fn __quantum__rt__bigint_get_data(input: *const BigInt) -> *const u8 {
25    ManuallyDrop::new((*input).to_signed_bytes_le()).as_ptr()
26}
27
28#[no_mangle]
29pub unsafe extern "C" fn __quantum__rt__bigint_get_length(input: *const BigInt) -> u32 {
30    let size = (*input).to_signed_bytes_le().len();
31    size.try_into()
32        .expect("Length of bigint representation too large for 32-bit integer.")
33}
34
35#[no_mangle]
36pub unsafe extern "C" fn __quantum__rt__bigint_update_reference_count(
37    input: *const BigInt,
38    update: i32,
39) {
40    update_counts(input, update, false);
41}
42
43#[no_mangle]
44pub unsafe extern "C" fn __quantum__rt__bigint_negate(input: *const BigInt) -> *const BigInt {
45    Rc::into_raw(Rc::new(&(*input) * -1))
46}
47
48#[no_mangle]
49pub unsafe extern "C" fn __quantum__rt__bigint_add(
50    lhs: *const BigInt,
51    rhs: *const BigInt,
52) -> *const BigInt {
53    Rc::into_raw(Rc::new(&(*lhs) + &(*rhs)))
54}
55
56#[no_mangle]
57pub unsafe extern "C" fn __quantum__rt__bigint_subtract(
58    lhs: *const BigInt,
59    rhs: *const BigInt,
60) -> *const BigInt {
61    Rc::into_raw(Rc::new(&(*lhs) - &(*rhs)))
62}
63
64#[no_mangle]
65pub unsafe extern "C" fn __quantum__rt__bigint_multiply(
66    lhs: *const BigInt,
67    rhs: *const BigInt,
68) -> *const BigInt {
69    Rc::into_raw(Rc::new(&(*lhs) * &(*rhs)))
70}
71
72#[no_mangle]
73pub unsafe extern "C" fn __quantum__rt__bigint_divide(
74    lhs: *const BigInt,
75    rhs: *const BigInt,
76) -> *const BigInt {
77    Rc::into_raw(Rc::new(&(*lhs) / &(*rhs)))
78}
79
80#[no_mangle]
81pub unsafe extern "C" fn __quantum__rt__bigint_modulus(
82    lhs: *const BigInt,
83    rhs: *const BigInt,
84) -> *const BigInt {
85    Rc::into_raw(Rc::new(&(*lhs) % &(*rhs)))
86}
87
88#[no_mangle]
89pub unsafe extern "C" fn __quantum__rt__bigint_power(
90    base: *const BigInt,
91    exponent: u32,
92) -> *const BigInt {
93    Rc::into_raw(Rc::new((*base).pow(exponent)))
94}
95
96#[no_mangle]
97pub unsafe extern "C" fn __quantum__rt__bigint_bitand(
98    lhs: *const BigInt,
99    rhs: *const BigInt,
100) -> *const BigInt {
101    Rc::into_raw(Rc::new(&(*lhs) & &(*rhs)))
102}
103
104#[no_mangle]
105pub unsafe extern "C" fn __quantum__rt__bigint_bitor(
106    lhs: *const BigInt,
107    rhs: *const BigInt,
108) -> *const BigInt {
109    Rc::into_raw(Rc::new(&(*lhs) | &(*rhs)))
110}
111
112#[no_mangle]
113pub unsafe extern "C" fn __quantum__rt__bigint_bitxor(
114    lhs: *const BigInt,
115    rhs: *const BigInt,
116) -> *const BigInt {
117    Rc::into_raw(Rc::new(&(*lhs) ^ &(*rhs)))
118}
119
120#[no_mangle]
121pub unsafe extern "C" fn __quantum__rt__bigint_bitnot(input: *const BigInt) -> *const BigInt {
122    Rc::into_raw(Rc::new(!&(*input)))
123}
124
125#[no_mangle]
126pub unsafe extern "C" fn __quantum__rt__bigint_shiftleft(
127    input: *const BigInt,
128    amount: u64,
129) -> *const BigInt {
130    Rc::into_raw(Rc::new(&(*input) << amount))
131}
132
133#[no_mangle]
134pub unsafe extern "C" fn __quantum__rt__bigint_shiftright(
135    input: *const BigInt,
136    amount: u64,
137) -> *const BigInt {
138    Rc::into_raw(Rc::new(&(*input) >> amount))
139}
140
141#[no_mangle]
142pub unsafe extern "C" fn __quantum__rt__bigint_equal(
143    lhs: *const BigInt,
144    rhs: *const BigInt,
145) -> bool {
146    (*lhs) == (*rhs)
147}
148
149#[no_mangle]
150pub unsafe extern "C" fn __quantum__rt__bigint_greater(
151    lhs: *const BigInt,
152    rhs: *const BigInt,
153) -> bool {
154    (*lhs) > (*rhs)
155}
156
157#[no_mangle]
158pub unsafe extern "C" fn __quantum__rt__bigint_greater_eq(
159    lhs: *const BigInt,
160    rhs: *const BigInt,
161) -> bool {
162    (*lhs) >= (*rhs)
163}
164
165#[cfg(test)]
166mod tests {
167    use std::convert::TryInto;
168
169    use super::*;
170
171    #[test]
172    fn test_bigint_create_from_int() {
173        let bigint_0 = __quantum__rt__bigint_create_i64(42);
174        unsafe {
175            assert_eq!(*bigint_0, (42).into());
176            // Note that the test must decrement the reference count on any created items to ensure
177            // they are cleaned up and tests can pass with address sanitizer.
178            __quantum__rt__bigint_update_reference_count(bigint_0, -1);
179        }
180    }
181
182    #[test]
183    fn test_bigint_create_from_array() {
184        let bytes = 9_223_372_036_854_775_807_i64.to_le_bytes();
185        unsafe {
186            let bigint_1 =
187                __quantum__rt__bigint_create_array(bytes.len().try_into().unwrap(), bytes.as_ptr());
188            assert_eq!(*bigint_1, (9_223_372_036_854_775_807_i64).into());
189            __quantum__rt__bigint_update_reference_count(bigint_1, -1);
190        }
191    }
192
193    #[test]
194    fn test_bigint_arithmetic() {
195        let bigint_0 = __quantum__rt__bigint_create_i64(42);
196        let bigint_1 = __quantum__rt__bigint_create_i64(3);
197        unsafe {
198            let bigint_2 = __quantum__rt__bigint_add(bigint_0, bigint_1);
199            assert_eq!(*bigint_2, (45).into());
200            let bigint_3 = __quantum__rt__bigint_subtract(bigint_2, bigint_1);
201            assert_eq!(*bigint_3, (42).into());
202            let bigint_4 = __quantum__rt__bigint_divide(bigint_3, bigint_1);
203            assert_eq!(*bigint_4, (14).into());
204            let bigint_5 = __quantum__rt__bigint_multiply(bigint_4, bigint_1);
205            assert_eq!(*bigint_5, (42).into());
206            let bigint_6 = __quantum__rt__bigint_modulus(bigint_5, bigint_1);
207            assert_eq!(*bigint_6, (0).into());
208            let bigint_7 = __quantum__rt__bigint_negate(bigint_5);
209            assert_eq!(*bigint_7, (-42).into());
210            let bigint_8 = __quantum__rt__bigint_power(bigint_7, 3);
211            assert_eq!(*bigint_8, (-74088).into());
212            __quantum__rt__bigint_update_reference_count(bigint_8, -1);
213            __quantum__rt__bigint_update_reference_count(bigint_7, -1);
214            __quantum__rt__bigint_update_reference_count(bigint_6, -1);
215            __quantum__rt__bigint_update_reference_count(bigint_5, -1);
216            __quantum__rt__bigint_update_reference_count(bigint_4, -1);
217            __quantum__rt__bigint_update_reference_count(bigint_3, -1);
218            __quantum__rt__bigint_update_reference_count(bigint_2, -1);
219            __quantum__rt__bigint_update_reference_count(bigint_1, -1);
220            __quantum__rt__bigint_update_reference_count(bigint_0, -1);
221        }
222    }
223
224    #[test]
225    fn test_bigint_bitops() {
226        let bigint_0 = __quantum__rt__bigint_create_i64(42);
227        let bigint_1 = __quantum__rt__bigint_create_i64(3);
228        unsafe {
229            let bigint_2 = __quantum__rt__bigint_bitand(bigint_0, bigint_1);
230            assert_eq!(*bigint_2, (2).into());
231            let bigint_3 = __quantum__rt__bigint_bitor(bigint_0, bigint_1);
232            assert_eq!(*bigint_3, (43).into());
233            let bigint_4 = __quantum__rt__bigint_bitxor(bigint_0, bigint_3);
234            assert_eq!(*bigint_4, (1).into());
235            let bigint_5 = __quantum__rt__bigint_bitnot(bigint_4);
236            assert_eq!(*bigint_5, (-2).into());
237            let bigint_6 = __quantum__rt__bigint_shiftleft(bigint_0, 2);
238            assert_eq!(*bigint_6, (168).into());
239            let bigint_7 = __quantum__rt__bigint_shiftright(bigint_6, 3);
240            assert_eq!(*bigint_7, (21).into());
241            __quantum__rt__bigint_update_reference_count(bigint_7, -1);
242            __quantum__rt__bigint_update_reference_count(bigint_6, -1);
243            __quantum__rt__bigint_update_reference_count(bigint_5, -1);
244            __quantum__rt__bigint_update_reference_count(bigint_4, -1);
245            __quantum__rt__bigint_update_reference_count(bigint_3, -1);
246            __quantum__rt__bigint_update_reference_count(bigint_2, -1);
247            __quantum__rt__bigint_update_reference_count(bigint_1, -1);
248            __quantum__rt__bigint_update_reference_count(bigint_0, -1);
249        }
250    }
251
252    #[test]
253    fn test_bigint_comparisons() {
254        let bigint_0 = __quantum__rt__bigint_create_i64(42);
255        let bigint_1 = __quantum__rt__bigint_create_i64(43);
256        let bigint_2 = __quantum__rt__bigint_create_i64(42);
257        unsafe {
258            assert!(__quantum__rt__bigint_greater(bigint_1, bigint_0));
259            assert!(!__quantum__rt__bigint_greater(bigint_0, bigint_1));
260            assert!(__quantum__rt__bigint_equal(bigint_0, bigint_2));
261            assert!(__quantum__rt__bigint_greater_eq(bigint_0, bigint_2));
262            assert!(__quantum__rt__bigint_greater_eq(bigint_1, bigint_2));
263            assert!(!__quantum__rt__bigint_greater_eq(bigint_0, bigint_1));
264            __quantum__rt__bigint_update_reference_count(bigint_2, -1);
265            __quantum__rt__bigint_update_reference_count(bigint_1, -1);
266            __quantum__rt__bigint_update_reference_count(bigint_0, -1);
267        }
268    }
269}