Skip to content

Instantly share code, notes, and snippets.

@m1el
Last active May 13, 2024 10:51
Show Gist options
  • Save m1el/4cbf714815c5efefa6353d3d95275778 to your computer and use it in GitHub Desktop.
Save m1el/4cbf714815c5efefa6353d3d95275778 to your computer and use it in GitHub Desktop.
// 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