hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

bits.ha (5316B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use types;
      5 
      6 
      7 // Rotates a 32-bit unsigned integer left by k bits. k may be negative to rotate
      8 // right instead, or see [[rotr32]].
      9 export fn rotl32(x: u32, k: int) u32 = {
     10 	const n = 32u32;
     11 	const s = k: u32 & (n - 1);
     12 	return x << s | x >> (n - s);
     13 };
     14 
     15 // Rotates a 32-bit unsigned integer right by k bits. k may be negative to
     16 // rotate left instead, or see [[rotl32]].
     17 export fn rotr32(x: u32, k: int) u32 = rotl32(x, -k);
     18 
     19 @test fn lrot32() void = {
     20 	let a = 0b11110000111100001111000011110000u32;
     21 	assert(rotl32(a, 2) == 0b11000011110000111100001111000011u32);
     22 	assert(rotl32(a, -2) == 0b00111100001111000011110000111100u32);
     23 	assert(rotl32(a, 32) == 0b11110000111100001111000011110000u32);
     24 	assert(rotl32(a, 64) == 0b11110000111100001111000011110000u32);
     25 };
     26 
     27 // Rotates a 64-bit unsigned integer left by k bits. k may be negative to rotate
     28 // right instead, or see [[rotr64]].
     29 export fn rotl64(x: u64, k: int) u64 = {
     30 	const n = 64u64;
     31 	const s = k: u64 & (n - 1);
     32 	return x << s | x >> (n - s);
     33 };
     34 
     35 // Rotates a 64-bit unsigned integer right by k bits. k may be negative to rotate
     36 // left instead, or see [[rotl64]].
     37 export fn rotr64(x: u64, k: int) u64 = rotl64(x, -k);
     38 
     39 @test fn lrot64() void = {
     40 	let a = 1u64;
     41 	assert(rotl64(a, 1) == 0b10);
     42 	assert(rotl64(a, -1) == 0b1000000000000000000000000000000000000000000000000000000000000000);
     43 	assert(rotl64(a, 39) == (1u64 << 39));
     44 
     45 	let a = 0b1111000011110000111100001111000011110000111100001111000011110000u64;
     46 	assert(rotl64(a, 64) == a);
     47 	assert(rotl64(a, 0) == a);
     48 	assert(rotl64(a, 2) == 0b1100001111000011110000111100001111000011110000111100001111000011u64);
     49 	assert(rotl64(a, -2) == 0b0011110000111100001111000011110000111100001111000011110000111100u64);
     50 
     51 };
     52 
     53 // Stores the xor of 'a' and 'b' into 'dest'. All parameters must have the same
     54 // length. 'dest' may be the same slice as 'a' and/or 'b'.
     55 export fn xor(dest: []u8, a: []u8, b: []u8) void = {
     56 	assert(len(dest) == len(a) && len(dest) == len(b),
     57 		"dest, a and b must have the same length");
     58 
     59 	for (let i = 0z; i < len(dest); i += 1) {
     60 		dest[i] = a[i] ^ b[i];
     61 	};
     62 };
     63 
     64 // Compare two byte slices in constant time.
     65 //
     66 // Returns 1 if the two slices have the same contents, 0 otherwise.
     67 export fn eqslice(x: []u8, y: []u8) int = {
     68 	assert(len(x) == len(y), "slices must have the same length");
     69 	let v: u8 = 0;
     70 	for (let i = 0z; i < len(x); i += 1) {
     71 		v |= x[i] ^ y[i];
     72 	};
     73 	return equ8(v, 0);
     74 };
     75 
     76 @test fn eqslice() void = {
     77 	assert(eqslice([], []) == 1);
     78 	assert(eqslice([0], [0]) == 1);
     79 	assert(eqslice([1], [0]) == 0);
     80 	assert(eqslice([1, 0], [0, 0]) == 0);
     81 	assert(eqslice([0, 0], [0, 0]) == 1);
     82 
     83 	assert(eqslice([0x12, 0xAB], [0x12, 0xAB]) == 1);
     84 	assert(eqslice([0x12, 0xAB], [0x12, 0xAC]) == 0);
     85 	assert(eqslice([0x12, 0xAB], [0x11, 0xAB]) == 0);
     86 };
     87 
     88 // Compare two bytes in constant time. Returns 1 if the bytes are the same
     89 // value, 0 otherwise.
     90 export fn equ8(x: u8, y: u8) int = ((((x ^ y) : u32) - 1) >> 31) : int;
     91 
     92 // Returns x if ctl == 1 and y if ctl == 0.
     93 export fn muxu32(ctl: u32, x: u32, y: u32) u32 = y ^ ((-(ctl: i32)): u32 & (x ^ y));
     94 
     95 @test fn muxu32() void = {
     96 	assert(muxu32(1, 0x4, 0xff) == 0x4);
     97 	assert(muxu32(0, 0x4, 0xff) == 0xff);
     98 };
     99 
    100 // Negates first bit.
    101 export fn notu32(x: u32) u32 = x ^ 1;
    102 
    103 // Compares 'x' and 'y'. Returns 1 if they are equal or 0 otherwise.
    104 export fn equ32(x: u32, y: u32) u32 = {
    105 	let q = x ^ y;
    106 	return ((q | -(q: i32): u32) >> 31) ^ 1;
    107 };
    108 
    109 @test fn equ32() void = {
    110 	assert(equ32(0x4f, 0x4f) == 1);
    111 	assert(equ32(0x4f, 0x0) == 0);
    112 	assert(equ32(0x2, 0x6) == 0);
    113 };
    114 
    115 // Returns 1 if 'x' is zero or 0 if not.
    116 export fn eq0u32(x: u32) u32 = {
    117 	return ~(x | -x) >> 31;
    118 };
    119 
    120 @test fn eq0u32() void = {
    121 	assert(eq0u32(0) == 1);
    122 	assert(eq0u32(1) == 0);
    123 	assert(eq0u32(0x1234) == 0);
    124 	assert(eq0u32(types::U32_MAX) == 0);
    125 };
    126 
    127 // Returns 1 if x != y and 0 otherwise.
    128 export fn nequ32(x: u32, y: u32) u32 = {
    129 	let q = x ^ y;
    130 	return (q | -(q: i32): u32) >> 31;
    131 };
    132 
    133 // Returns 1 if x > y and 0 otherwise.
    134 export fn gtu32(x: u32, y: u32) u32 = {
    135 	let z: u32 = y - x;
    136 	return (z ^ ((x ^ y) & (x ^ z))) >> 31;
    137 };
    138 
    139 @test fn gtu32() void = {
    140 	assert(gtu32(1, 0) == 1);
    141 	assert(gtu32(0, 1) == 0);
    142 	assert(gtu32(0, 0) == 0);
    143 
    144 	assert(gtu32(0xf3, 0xf2) == 1);
    145 	assert(gtu32(0x20, 0xff) == 0);
    146 	assert(gtu32(0x23, 0x23) == 0);
    147 };
    148 
    149 // Returns 1 if x >= y and 0 otherwise.
    150 export fn geu32(x: u32, y: u32) u32 = notu32(gtu32(y, x));
    151 
    152 // Returns 1 if x < y and 0 otherwise.
    153 export fn ltu32(x: u32, y: u32) u32 = gtu32(y, x);
    154 
    155 // Returns 1 if x <= y and 0 otherwise.
    156 export fn leu32(x: u32, y: u32) u32 = notu32(gtu32(x, y));
    157 
    158 // Compares 'x' with 'y'. Returns -1 if x < y, 0 if x == y and 1 if x > x.
    159 export fn cmpu32(x: u32, y: u32) i32 = gtu32(x, y): i32 | -(gtu32(y, x): i32);
    160 
    161 @test fn cmpu32() void = {
    162 	assert(cmpu32(0, 0) == 0);
    163 	assert(cmpu32(0x34, 0x34) == 0);
    164 
    165 	assert(cmpu32(0x12, 0x34) == -1);
    166 	assert(cmpu32(0x87, 0x34) == 1);
    167 };
    168 
    169 // Multiplies two u32 and returns result as u64.
    170 export fn mulu32(x: u32, y: u32) u64 = x: u64 * y: u64;
    171 
    172 // Copies 'src' to 'dest' if 'ctl' == 1
    173 export fn ccopyu32(ctl: u32, dest: []u32, src: const []u32) void = {
    174 	for (let i = 0z; i < len(dest); i += 1) {
    175 		const x = src[i];
    176 		const y = dest[i];
    177 
    178 		dest[i] = muxu32(ctl, x, y);
    179 	};
    180 };