diff --git a/rules/builtin/ir_refcount.json b/rules/builtin/ir_refcount.json new file mode 100644 index 00000000..6d2c8081 --- /dev/null +++ b/rules/builtin/ir_refcount.json @@ -0,0 +1,146 @@ +{ + "f10": { + "body": [ + { + "text": "let (val, ovf) = " + }, + { + "method_call": { + "receiver": [ + { + "placeholder": { + "arg": 0, + "access": "read" + } + } + ], + "body": [ + { + "text": ".overflowing_mul(" + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": ")" + } + ] + } + }, + { + "text": ";\n " + }, + { + "method_call": { + "receiver": [ + { + "placeholder": { + "arg": 2, + "access": "read" + } + } + ], + "body": [ + { + "text": ".write(val)" + } + ] + } + }, + { + "text": ";\n ovf" + } + ], + "multi_statement": true, + "params": { + "a0": { + "type": "i64" + }, + "a1": { + "type": "i64" + }, + "a2": { + "type": "Ptr", + "is_refcount_pointer": true + } + }, + "return_type": { + "type": "bool" + } + }, + "f9": { + "body": [ + { + "text": "let (val, ovf) = " + }, + { + "method_call": { + "receiver": [ + { + "placeholder": { + "arg": 0, + "access": "read" + } + } + ], + "body": [ + { + "text": ".overflowing_mul(" + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": ")" + } + ] + } + }, + { + "text": ";\n " + }, + { + "method_call": { + "receiver": [ + { + "placeholder": { + "arg": 2, + "access": "read" + } + } + ], + "body": [ + { + "text": ".write(val)" + } + ] + } + }, + { + "text": ";\n ovf" + } + ], + "multi_statement": true, + "params": { + "a0": { + "type": "i64" + }, + "a1": { + "type": "i64" + }, + "a2": { + "type": "Ptr", + "is_refcount_pointer": true + } + }, + "return_type": { + "type": "bool" + } + } +} diff --git a/rules/builtin/ir_unsafe.json b/rules/builtin/ir_unsafe.json index 08934062..16b7c2cd 100644 --- a/rules/builtin/ir_unsafe.json +++ b/rules/builtin/ir_unsafe.json @@ -20,6 +20,67 @@ "type": "usize" } }, + "f10": { + "body": [ + { + "text": "let (val, ovf) = " + }, + { + "method_call": { + "receiver": [ + { + "placeholder": { + "arg": 0, + "access": "read" + } + } + ], + "body": [ + { + "text": ".overflowing_mul(" + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": ")" + } + ] + } + }, + { + "text": ";\n *" + }, + { + "placeholder": { + "arg": 2, + "access": "write" + } + }, + { + "text": " = val;\n ovf" + } + ], + "multi_statement": true, + "params": { + "a0": { + "type": "i64" + }, + "a1": { + "type": "i64" + }, + "a2": { + "type": "*mut i64", + "is_unsafe_pointer": true + } + }, + "return_type": { + "type": "bool" + } + }, "f2": { "body": [ { @@ -170,5 +231,130 @@ "return_type": { "type": "u64" } + }, + "f7": { + "body": [ + { + "method_call": { + "receiver": [ + { + "placeholder": { + "arg": 0, + "access": "read" + } + } + ], + "body": [ + { + "text": ".trailing_zeros()" + } + ] + } + }, + { + "text": " as i32" + } + ], + "params": { + "a0": { + "type": "u64" + } + }, + "return_type": { + "type": "i32" + } + }, + "f8": { + "body": [ + { + "method_call": { + "receiver": [ + { + "placeholder": { + "arg": 0, + "access": "read" + } + } + ], + "body": [ + { + "text": ".count_ones()" + } + ] + } + }, + { + "text": " as i32" + } + ], + "params": { + "a0": { + "type": "u64" + } + }, + "return_type": { + "type": "i32" + } + }, + "f9": { + "body": [ + { + "text": "let (val, ovf) = " + }, + { + "method_call": { + "receiver": [ + { + "placeholder": { + "arg": 0, + "access": "read" + } + } + ], + "body": [ + { + "text": ".overflowing_mul(" + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": ")" + } + ] + } + }, + { + "text": ";\n *" + }, + { + "placeholder": { + "arg": 2, + "access": "write" + } + }, + { + "text": " = val;\n ovf" + } + ], + "multi_statement": true, + "params": { + "a0": { + "type": "i64" + }, + "a1": { + "type": "i64" + }, + "a2": { + "type": "*mut i64", + "is_unsafe_pointer": true + } + }, + "return_type": { + "type": "bool" + } } } diff --git a/rules/builtin/src.cpp b/rules/builtin/src.cpp index b74347c3..26da1699 100644 --- a/rules/builtin/src.cpp +++ b/rules/builtin/src.cpp @@ -19,3 +19,7 @@ unsigned short f4(unsigned short x) { return __builtin_bswap16(x); } unsigned int f5(unsigned int x) { return __builtin_bswap32(x); } unsigned long long f6(unsigned long long x) { return __builtin_bswap64(x); } #endif +int f7(unsigned long x) { return __builtin_ctzl(x); } +int f8(unsigned long x) { return __builtin_popcountl(x); } +bool f9(long a, long b, long *r) { return __builtin_mul_overflow(a, b, r); } +bool f10(long long a, long long b, long long *r) { return __builtin_mul_overflow(a, b, r); } diff --git a/rules/builtin/tgt_refcount.rs b/rules/builtin/tgt_refcount.rs new file mode 100644 index 00000000..0f076e1c --- /dev/null +++ b/rules/builtin/tgt_refcount.rs @@ -0,0 +1,15 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +use libcc2rs::*; + +fn f9(a0: i64, a1: i64, a2: Ptr) -> bool { + let (val, ovf) = a0.overflowing_mul(a1); + a2.write(val); + ovf +} +fn f10(a0: i64, a1: i64, a2: Ptr) -> bool { + let (val, ovf) = a0.overflowing_mul(a1); + a2.write(val); + ovf +} diff --git a/rules/builtin/tgt_unsafe.rs b/rules/builtin/tgt_unsafe.rs index 077b4c5f..d2f94f66 100644 --- a/rules/builtin/tgt_unsafe.rs +++ b/rules/builtin/tgt_unsafe.rs @@ -19,3 +19,19 @@ unsafe fn f5(a0: u32) -> u32 { unsafe fn f6(a0: u64) -> u64 { a0.swap_bytes() } +unsafe fn f7(a0: u64) -> i32 { + a0.trailing_zeros() as i32 +} +unsafe fn f8(a0: u64) -> i32 { + a0.count_ones() as i32 +} +unsafe fn f9(a0: i64, a1: i64, a2: *mut i64) -> bool { + let (val, ovf) = a0.overflowing_mul(a1); + *a2 = val; + ovf +} +unsafe fn f10(a0: i64, a1: i64, a2: *mut i64) -> bool { + let (val, ovf) = a0.overflowing_mul(a1); + *a2 = val; + ovf +} diff --git a/rules/src/modules.rs b/rules/src/modules.rs index 0da0327e..2b5d751c 100644 --- a/rules/src/modules.rs +++ b/rules/src/modules.rs @@ -16,6 +16,8 @@ pub mod assert_tgt_unsafe; pub mod brotli_tgt_refcount; #[path = r#"../brotli/tgt_unsafe.rs"#] pub mod brotli_tgt_unsafe; +#[path = r#"../builtin/tgt_refcount.rs"#] +pub mod builtin_tgt_refcount; #[path = r#"../builtin/tgt_unsafe.rs"#] pub mod builtin_tgt_unsafe; #[path = r#"../carray/tgt_refcount.rs"#] diff --git a/tests/unit/builtin.c b/tests/unit/builtin.c new file mode 100644 index 00000000..a3a15328 --- /dev/null +++ b/tests/unit/builtin.c @@ -0,0 +1,82 @@ +#include +#include +#if defined(__linux__) +#include +#endif + +static void test_expect(void) { + int x = 42; + assert(__builtin_expect(x == 42, 1)); +} + +static void test_ctz(void) { + assert(__builtin_ctz(8U) == 3); + assert(__builtin_ctz(1U) == 0); +} + +static void test_clz(void) { + assert(__builtin_clz(1U) == 31); + assert(__builtin_clz(0x80000000U) == 0); +} + +static void test_bswap16(void) { +#if defined(__linux__) + assert(bswap_16((unsigned short)0x1234) == 0x3412); +#else + assert(__builtin_bswap16((unsigned short)0x1234) == 0x3412); +#endif +} + +static void test_bswap32(void) { +#if defined(__linux__) + assert(bswap_32(0x12345678U) == 0x78563412U); +#else + assert(__builtin_bswap32(0x12345678U) == 0x78563412U); +#endif +} + +static void test_bswap64(void) { +#if defined(__linux__) + assert(bswap_64(0x0123456789ABCDEFULL) == 0xEFCDAB8967452301ULL); +#else + assert(__builtin_bswap64(0x0123456789ABCDEFULL) == 0xEFCDAB8967452301ULL); +#endif +} + +static void test_ctzl(void) { + assert(__builtin_ctzl(8UL) == 3); + assert(__builtin_ctzl(1UL) == 0); +} + +static void test_popcountl(void) { + assert(__builtin_popcountl(0UL) == 0); + assert(__builtin_popcountl(0xFFUL) == 8); +} + +static void test_mul_overflow_long(void) { + long r = 0; + assert(!__builtin_mul_overflow(3L, 7L, &r)); + assert(r == 21); + assert(__builtin_mul_overflow(LONG_MAX, 2L, &r)); +} + +static void test_mul_overflow_long_long(void) { + long long r = 0; + assert(!__builtin_mul_overflow(1000LL, 1000LL, &r)); + assert(r == 1000000); + assert(__builtin_mul_overflow(LLONG_MAX, 2LL, &r)); +} + +int main(void) { + test_expect(); + test_ctz(); + test_clz(); + test_bswap16(); + test_bswap32(); + test_bswap64(); + test_ctzl(); + test_popcountl(); + test_mul_overflow_long(); + test_mul_overflow_long_long(); + return 0; +} diff --git a/tests/unit/out/refcount/builtin.rs b/tests/unit/out/refcount/builtin.rs new file mode 100644 index 00000000..03266193 --- /dev/null +++ b/tests/unit/out/refcount/builtin.rs @@ -0,0 +1,87 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn test_expect_0() { + let x: Value = Rc::new(RefCell::new(42)); + assert!((((((*x.borrow()) == 42) as i32) as i64) != 0)); +} +pub fn test_ctz_1() { + assert!((((8_u32.trailing_zeros() as i32 == 3) as i32) != 0)); + assert!((((1_u32.trailing_zeros() as i32 == 0) as i32) != 0)); +} +pub fn test_clz_2() { + assert!((((1_u32.leading_zeros() as i32 == 31) as i32) != 0)); + assert!((((2147483648_u32.leading_zeros() as i32 == 0) as i32) != 0)); +} +pub fn test_bswap16_3() { + assert!((((((4660 as u16).swap_bytes() as i32) == 13330) as i32) != 0)); +} +pub fn test_bswap32_4() { + assert!((((305419896_u32.swap_bytes() == 2018915346_u32) as i32) != 0)); +} +pub fn test_bswap64_5() { + assert!((((81985529216486895_u64.swap_bytes() == 17279655951921914625_u64) as i32) != 0)); +} +pub fn test_ctzl_6() { + assert!((((8_u64.trailing_zeros() as i32 == 3) as i32) != 0)); + assert!((((1_u64.trailing_zeros() as i32 == 0) as i32) != 0)); +} +pub fn test_popcountl_7() { + assert!((((0_u64.count_ones() as i32 == 0) as i32) != 0)); + assert!((((255_u64.count_ones() as i32 == 8) as i32) != 0)); +} +pub fn test_mul_overflow_long_8() { + let r: Value = Rc::new(RefCell::new(0_i64)); + assert!( + ((!{ + let (val, ovf) = 3_i64.overflowing_mul(7_i64); + (r.as_pointer()).write(val); + ovf + } as i32) + != 0) + ); + assert!(((((*r.borrow()) == 21_i64) as i32) != 0)); + assert!({ + let (val, ovf) = 9223372036854775807_i64.overflowing_mul(2_i64); + (r.as_pointer()).write(val); + ovf + }); +} +pub fn test_mul_overflow_long_long_9() { + let r: Value = Rc::new(RefCell::new(0_i64)); + assert!( + ((!{ + let (val, ovf) = 1000_i64.overflowing_mul(1000_i64); + (r.as_pointer()).write(val); + ovf + } as i32) + != 0) + ); + assert!(((((*r.borrow()) == 1000000_i64) as i32) != 0)); + assert!({ + let (val, ovf) = 9223372036854775807_i64.overflowing_mul(2_i64); + (r.as_pointer()).write(val); + ovf + }); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + ({ test_expect_0() }); + ({ test_ctz_1() }); + ({ test_clz_2() }); + ({ test_bswap16_3() }); + ({ test_bswap32_4() }); + ({ test_bswap64_5() }); + ({ test_ctzl_6() }); + ({ test_popcountl_7() }); + ({ test_mul_overflow_long_8() }); + ({ test_mul_overflow_long_long_9() }); + return 0; +} diff --git a/tests/unit/out/unsafe/builtin.rs b/tests/unit/out/unsafe/builtin.rs new file mode 100644 index 00000000..be8f48b9 --- /dev/null +++ b/tests/unit/out/unsafe/builtin.rs @@ -0,0 +1,89 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn test_expect_0() { + let mut x: i32 = 42; + assert!((((((x) == (42)) as i32) as i64) != 0)); +} +pub unsafe fn test_ctz_1() { + assert!(((((8_u32.trailing_zeros() as i32) == (3)) as i32) != 0)); + assert!(((((1_u32.trailing_zeros() as i32) == (0)) as i32) != 0)); +} +pub unsafe fn test_clz_2() { + assert!(((((1_u32.leading_zeros() as i32) == (31)) as i32) != 0)); + assert!(((((2147483648_u32.leading_zeros() as i32) == (0)) as i32) != 0)); +} +pub unsafe fn test_bswap16_3() { + assert!((((((4660 as u16).swap_bytes() as i32) == (13330)) as i32) != 0)); +} +pub unsafe fn test_bswap32_4() { + assert!(((((305419896_u32.swap_bytes()) == (2018915346_u32)) as i32) != 0)); +} +pub unsafe fn test_bswap64_5() { + assert!(((((81985529216486895_u64.swap_bytes()) == (17279655951921914625_u64)) as i32) != 0)); +} +pub unsafe fn test_ctzl_6() { + assert!(((((8_u64.trailing_zeros() as i32) == (3)) as i32) != 0)); + assert!(((((1_u64.trailing_zeros() as i32) == (0)) as i32) != 0)); +} +pub unsafe fn test_popcountl_7() { + assert!(((((0_u64.count_ones() as i32) == (0)) as i32) != 0)); + assert!(((((255_u64.count_ones() as i32) == (8)) as i32) != 0)); +} +pub unsafe fn test_mul_overflow_long_8() { + let mut r: i64 = 0_i64; + assert!( + ((!{ + let (val, ovf) = 3_i64.overflowing_mul(7_i64); + *(&mut r as *mut i64) = val; + ovf + } as i32) + != 0) + ); + assert!(((((r) == (21_i64)) as i32) != 0)); + assert!({ + let (val, ovf) = 9223372036854775807_i64.overflowing_mul(2_i64); + *(&mut r as *mut i64) = val; + ovf + }); +} +pub unsafe fn test_mul_overflow_long_long_9() { + let mut r: i64 = 0_i64; + assert!( + ((!{ + let (val, ovf) = 1000_i64.overflowing_mul(1000_i64); + *(&mut r as *mut i64) = val; + ovf + } as i32) + != 0) + ); + assert!(((((r) == (1000000_i64)) as i32) != 0)); + assert!({ + let (val, ovf) = 9223372036854775807_i64.overflowing_mul(2_i64); + *(&mut r as *mut i64) = val; + ovf + }); +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + (unsafe { test_expect_0() }); + (unsafe { test_ctz_1() }); + (unsafe { test_clz_2() }); + (unsafe { test_bswap16_3() }); + (unsafe { test_bswap32_4() }); + (unsafe { test_bswap64_5() }); + (unsafe { test_ctzl_6() }); + (unsafe { test_popcountl_7() }); + (unsafe { test_mul_overflow_long_8() }); + (unsafe { test_mul_overflow_long_long_9() }); + return 0; +}