Last active
May 13, 2024 10:51
-
-
Save m1el/4cbf714815c5efefa6353d3d95275778 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://godbolt.org/z/KoMfsEszq | |
// https://godbolt.org/z/18PKTE6Ej | |
// https://godbolt.org/z/vGs9Eeoo5 | |
// Base on Hacker's Delight section 2.3 THE 16 BINARY LOGICAL OPERATIONS | |
#![feature(portable_simd)] | |
extern crate core; | |
#[repr(u8)] | |
pub enum Op { | |
ConstZero = 0b0000, | |
And = 0b1000, | |
AndNot = 0b0100, | |
First = 0b1100, | |
NotAnd = 0b0010, | |
Second = 0b1010, | |
Xor = 0b0110, | |
Or = 0b1110, | |
NOr = 0b0001, | |
Eq = 0b1001, | |
NotSecond = 0b0101, | |
OrNot = 0b1101, | |
NotFirst = 0b0011, | |
NotOr = 0b1011, | |
NAnd = 0b0111, | |
ConstOne = 0b1111, | |
} | |
pub fn apply_binary_op(x: u32, y: u32, op: Op) -> u32 { | |
let op = op as u8; | |
let select_00 = (((op >> 0) & 1) as u32).wrapping_neg(); | |
let bit_00 = !x & !y; | |
let select_01 = (((op >> 1) & 1) as u32).wrapping_neg(); | |
let bit_01 = !x & y; | |
let select_10 = (((op >> 2) & 1) as u32).wrapping_neg(); | |
let bit_10 = x & !y; | |
let select_11 = (((op >> 3) & 1) as u32).wrapping_neg(); | |
let bit_11 = x & y; | |
(bit_00 & select_00) | |
| (bit_01 & select_01) | |
| (bit_10 & select_10) | |
| (bit_11 & select_11) | |
} | |
pub fn apply_binary_op_simd(x: u32, y: u32, op: Op) -> u32 { | |
use core::simd::Simd; | |
let select = (Simd::splat(op as u32) >> Simd::from_array([0, 1, 2, 3])) & Simd::splat(1); | |
let select = Simd::splat(0) - select; | |
let even = Simd::from_array([!0, 0, !0, 0]); | |
let half = Simd::from_array([!0, !0, 0, 0]); | |
let x = Simd::splat(x) ^ half; | |
let y = Simd::splat(y) ^ even; | |
let bits = (x & y) & select; | |
IntoIterator::into_iter(bits.to_array()).fold(0, |a, b| a | b) | |
} | |
fn main() { | |
let x = 0x1337; | |
let y = 0x3713; | |
assert_eq!(x ^ y, apply_binary_op(x, y, Op::Xor)); | |
assert_eq!(x ^ y, apply_binary_op_simd(x, y, Op::Xor)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment