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 };