mirror of
https://github.com/roc-lang/roc.git
synced 2025-07-23 06:25:10 +00:00
add Num.count*Bits functions
This commit is contained in:
parent
fbaa257cef
commit
785da377c8
11 changed files with 207 additions and 8 deletions
|
@ -86,6 +86,10 @@ comptime {
|
||||||
num.exportMulWithOverflow(T, WIDEINTS[i], ROC_BUILTINS ++ "." ++ NUM ++ ".mul_with_overflow.");
|
num.exportMulWithOverflow(T, WIDEINTS[i], ROC_BUILTINS ++ "." ++ NUM ++ ".mul_with_overflow.");
|
||||||
num.exportMulOrPanic(T, WIDEINTS[i], ROC_BUILTINS ++ "." ++ NUM ++ ".mul_or_panic.");
|
num.exportMulOrPanic(T, WIDEINTS[i], ROC_BUILTINS ++ "." ++ NUM ++ ".mul_or_panic.");
|
||||||
num.exportMulSaturatedInt(T, WIDEINTS[i], ROC_BUILTINS ++ "." ++ NUM ++ ".mul_saturated.");
|
num.exportMulSaturatedInt(T, WIDEINTS[i], ROC_BUILTINS ++ "." ++ NUM ++ ".mul_saturated.");
|
||||||
|
|
||||||
|
num.exportCountLeadingZeroBits(T, ROC_BUILTINS ++ "." ++ NUM ++ ".count_leading_zero_bits.");
|
||||||
|
num.exportCountTrailingZeroBits(T, ROC_BUILTINS ++ "." ++ NUM ++ ".count_trailing_zero_bits.");
|
||||||
|
num.exportCountOneBits(T, ROC_BUILTINS ++ "." ++ NUM ++ ".count_one_bits.");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline for (INTEGERS) |FROM| {
|
inline for (INTEGERS) |FROM| {
|
||||||
|
|
|
@ -460,3 +460,30 @@ pub fn exportMulOrPanic(comptime T: type, comptime W: type, comptime name: []con
|
||||||
}.func;
|
}.func;
|
||||||
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
|
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn exportCountLeadingZeroBits(comptime T: type, comptime name: []const u8) void {
|
||||||
|
comptime var f = struct {
|
||||||
|
fn func(self: T) callconv(.C) usize {
|
||||||
|
return @as(usize, @clz(T, self));
|
||||||
|
}
|
||||||
|
}.func;
|
||||||
|
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exportCountTrailingZeroBits(comptime T: type, comptime name: []const u8) void {
|
||||||
|
comptime var f = struct {
|
||||||
|
fn func(self: T) callconv(.C) usize {
|
||||||
|
return @as(usize, @ctz(T, self));
|
||||||
|
}
|
||||||
|
}.func;
|
||||||
|
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exportCountOneBits(comptime T: type, comptime name: []const u8) void {
|
||||||
|
comptime var f = struct {
|
||||||
|
fn func(self: T) callconv(.C) usize {
|
||||||
|
return @as(usize, @popCount(T, self));
|
||||||
|
}
|
||||||
|
}.func;
|
||||||
|
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
|
||||||
|
}
|
||||||
|
|
|
@ -68,6 +68,9 @@ interface Num
|
||||||
compare,
|
compare,
|
||||||
pow,
|
pow,
|
||||||
powInt,
|
powInt,
|
||||||
|
countLeadingZeroBits,
|
||||||
|
countTrailingZeroBits,
|
||||||
|
countOneBits,
|
||||||
addWrap,
|
addWrap,
|
||||||
addChecked,
|
addChecked,
|
||||||
addSaturated,
|
addSaturated,
|
||||||
|
@ -930,6 +933,46 @@ pow : Frac a, Frac a -> Frac a
|
||||||
## so large it causes an overflow.
|
## so large it causes an overflow.
|
||||||
powInt : Int a, Int a -> Int a
|
powInt : Int a, Int a -> Int a
|
||||||
|
|
||||||
|
## Counts the number of most-significant (leading in a big-Endian sense) zeroes in an integer.
|
||||||
|
##
|
||||||
|
## ```
|
||||||
|
## Num.countLeadingZeroBits 0b0001_1100u8
|
||||||
|
##
|
||||||
|
## 3
|
||||||
|
##
|
||||||
|
## Num.countLeadingZeroBits 0b0000_0000u8
|
||||||
|
##
|
||||||
|
## 8
|
||||||
|
## ```
|
||||||
|
countLeadingZeroBits : Int a -> Nat
|
||||||
|
|
||||||
|
## Counts the number of least-significant (trailing in a big-Endian sense) zeroes in an integer.
|
||||||
|
##
|
||||||
|
## ```
|
||||||
|
## Num.countTrailingZeroBits 0b0001_1100u8
|
||||||
|
##
|
||||||
|
## 2
|
||||||
|
##
|
||||||
|
## Num.countTrailingZeroBits 0b0000_0000u8
|
||||||
|
##
|
||||||
|
## 8
|
||||||
|
## ```
|
||||||
|
countTrailingZeroBits : Int a -> Nat
|
||||||
|
|
||||||
|
|
||||||
|
## Counts the number of set bits in an integer.
|
||||||
|
##
|
||||||
|
## ```
|
||||||
|
## Num.countOneBits 0b0001_1100u8
|
||||||
|
##
|
||||||
|
## 3
|
||||||
|
##
|
||||||
|
## Num.countOneBits 0b0000_0000u8
|
||||||
|
##
|
||||||
|
## 0
|
||||||
|
## ```
|
||||||
|
countOneBits : Int a -> Nat
|
||||||
|
|
||||||
addWrap : Int range, Int range -> Int range
|
addWrap : Int range, Int range -> Int range
|
||||||
|
|
||||||
## Add two numbers, clamping on the maximum representable number rather than
|
## Add two numbers, clamping on the maximum representable number rather than
|
||||||
|
|
|
@ -289,6 +289,12 @@ pub const NUM_MUL_CHECKED_INT: IntrinsicName = int_intrinsic!("roc_builtins.num.
|
||||||
pub const NUM_MUL_CHECKED_FLOAT: IntrinsicName =
|
pub const NUM_MUL_CHECKED_FLOAT: IntrinsicName =
|
||||||
float_intrinsic!("roc_builtins.num.mul_with_overflow");
|
float_intrinsic!("roc_builtins.num.mul_with_overflow");
|
||||||
|
|
||||||
|
pub const NUM_COUNT_LEADING_ZERO_BITS: IntrinsicName =
|
||||||
|
int_intrinsic!("roc_builtins.num.count_leading_zero_bits");
|
||||||
|
pub const NUM_COUNT_TRAILING_ZERO_BITS: IntrinsicName =
|
||||||
|
int_intrinsic!("roc_builtins.num.count_trailing_zero_bits");
|
||||||
|
pub const NUM_COUNT_ONE_BITS: IntrinsicName = int_intrinsic!("roc_builtins.num.count_one_bits");
|
||||||
|
|
||||||
pub const NUM_BYTES_TO_U16: &str = "roc_builtins.num.bytes_to_u16";
|
pub const NUM_BYTES_TO_U16: &str = "roc_builtins.num.bytes_to_u16";
|
||||||
pub const NUM_BYTES_TO_U32: &str = "roc_builtins.num.bytes_to_u32";
|
pub const NUM_BYTES_TO_U32: &str = "roc_builtins.num.bytes_to_u32";
|
||||||
|
|
||||||
|
|
|
@ -194,6 +194,9 @@ map_symbol_to_lowlevel_and_arity! {
|
||||||
NumShiftRightBy; NUM_SHIFT_RIGHT; 2,
|
NumShiftRightBy; NUM_SHIFT_RIGHT; 2,
|
||||||
NumShiftRightZfBy; NUM_SHIFT_RIGHT_ZERO_FILL; 2,
|
NumShiftRightZfBy; NUM_SHIFT_RIGHT_ZERO_FILL; 2,
|
||||||
NumToStr; NUM_TO_STR; 1,
|
NumToStr; NUM_TO_STR; 1,
|
||||||
|
NumCountLeadingZeroBits; NUM_COUNT_LEADING_ZERO_BITS; 1,
|
||||||
|
NumCountTrailingZeroBits; NUM_COUNT_TRAILING_ZERO_BITS; 1,
|
||||||
|
NumCountOneBits; NUM_COUNT_ONE_BITS; 1,
|
||||||
|
|
||||||
Eq; BOOL_STRUCTURAL_EQ; 2,
|
Eq; BOOL_STRUCTURAL_EQ; 2,
|
||||||
NotEq; BOOL_STRUCTURAL_NOT_EQ; 2,
|
NotEq; BOOL_STRUCTURAL_NOT_EQ; 2,
|
||||||
|
|
|
@ -848,9 +848,24 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NumAbs | NumNeg | NumRound | NumSqrtUnchecked | NumLogUnchecked | NumSin | NumCos
|
NumAbs
|
||||||
| NumCeiling | NumFloor | NumToFrac | NumIsFinite | NumAtan | NumAcos | NumAsin
|
| NumNeg
|
||||||
| NumToIntChecked => {
|
| NumRound
|
||||||
|
| NumSqrtUnchecked
|
||||||
|
| NumLogUnchecked
|
||||||
|
| NumSin
|
||||||
|
| NumCos
|
||||||
|
| NumCeiling
|
||||||
|
| NumFloor
|
||||||
|
| NumToFrac
|
||||||
|
| NumIsFinite
|
||||||
|
| NumAtan
|
||||||
|
| NumAcos
|
||||||
|
| NumAsin
|
||||||
|
| NumToIntChecked
|
||||||
|
| NumCountLeadingZeroBits
|
||||||
|
| NumCountTrailingZeroBits
|
||||||
|
| NumCountOneBits => {
|
||||||
arguments_with_layouts!((arg, arg_layout));
|
arguments_with_layouts!((arg, arg_layout));
|
||||||
|
|
||||||
match layout_interner.get(arg_layout) {
|
match layout_interner.get(arg_layout) {
|
||||||
|
@ -2045,6 +2060,19 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
|
||||||
complex_bitcast_check_size(env, result, return_type.into(), "cast_bitpacked")
|
complex_bitcast_check_size(env, result, return_type.into(), "cast_bitpacked")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
NumCountLeadingZeroBits => call_bitcode_fn(
|
||||||
|
env,
|
||||||
|
&[arg.into()],
|
||||||
|
&bitcode::NUM_COUNT_LEADING_ZERO_BITS[arg_width],
|
||||||
|
),
|
||||||
|
NumCountTrailingZeroBits => call_bitcode_fn(
|
||||||
|
env,
|
||||||
|
&[arg.into()],
|
||||||
|
&bitcode::NUM_COUNT_TRAILING_ZERO_BITS[arg_width],
|
||||||
|
),
|
||||||
|
NumCountOneBits => {
|
||||||
|
call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_COUNT_ONE_BITS[arg_width])
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!("Unrecognized int unary operation: {:?}", op);
|
unreachable!("Unrecognized int unary operation: {:?}", op);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1489,6 +1489,40 @@ impl<'a> LowLevelCall<'a> {
|
||||||
}
|
}
|
||||||
_ => panic_ret_type(),
|
_ => panic_ret_type(),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
NumCountLeadingZeroBits => match backend
|
||||||
|
.layout_interner
|
||||||
|
.get(backend.storage.symbol_layouts[&self.arguments[0]])
|
||||||
|
{
|
||||||
|
Layout::Builtin(Builtin::Int(width)) => {
|
||||||
|
self.load_args_and_call_zig(
|
||||||
|
backend,
|
||||||
|
&bitcode::NUM_COUNT_LEADING_ZERO_BITS[width],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => panic_ret_type(),
|
||||||
|
},
|
||||||
|
NumCountTrailingZeroBits => match backend
|
||||||
|
.layout_interner
|
||||||
|
.get(backend.storage.symbol_layouts[&self.arguments[0]])
|
||||||
|
{
|
||||||
|
Layout::Builtin(Builtin::Int(width)) => {
|
||||||
|
self.load_args_and_call_zig(
|
||||||
|
backend,
|
||||||
|
&bitcode::NUM_COUNT_TRAILING_ZERO_BITS[width],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => panic_ret_type(),
|
||||||
|
},
|
||||||
|
NumCountOneBits => match backend
|
||||||
|
.layout_interner
|
||||||
|
.get(backend.storage.symbol_layouts[&self.arguments[0]])
|
||||||
|
{
|
||||||
|
Layout::Builtin(Builtin::Int(width)) => {
|
||||||
|
self.load_args_and_call_zig(backend, &bitcode::NUM_COUNT_ONE_BITS[width]);
|
||||||
|
}
|
||||||
|
_ => panic_ret_type(),
|
||||||
|
},
|
||||||
NumRound => {
|
NumRound => {
|
||||||
self.load_args(backend);
|
self.load_args(backend);
|
||||||
let arg_type = CodeGenNumType::for_symbol(backend, self.arguments[0]);
|
let arg_type = CodeGenNumType::for_symbol(backend, self.arguments[0]);
|
||||||
|
|
|
@ -101,6 +101,9 @@ pub enum LowLevel {
|
||||||
NumToIntChecked,
|
NumToIntChecked,
|
||||||
NumToFloatChecked,
|
NumToFloatChecked,
|
||||||
NumToStr,
|
NumToStr,
|
||||||
|
NumCountLeadingZeroBits,
|
||||||
|
NumCountTrailingZeroBits,
|
||||||
|
NumCountOneBits,
|
||||||
Eq,
|
Eq,
|
||||||
NotEq,
|
NotEq,
|
||||||
And,
|
And,
|
||||||
|
@ -312,6 +315,9 @@ map_symbol_to_lowlevel! {
|
||||||
NumShiftRightBy <= NUM_SHIFT_RIGHT,
|
NumShiftRightBy <= NUM_SHIFT_RIGHT,
|
||||||
NumShiftRightZfBy <= NUM_SHIFT_RIGHT_ZERO_FILL,
|
NumShiftRightZfBy <= NUM_SHIFT_RIGHT_ZERO_FILL,
|
||||||
NumToStr <= NUM_TO_STR,
|
NumToStr <= NUM_TO_STR,
|
||||||
|
NumCountLeadingZeroBits <= NUM_COUNT_LEADING_ZERO_BITS,
|
||||||
|
NumCountTrailingZeroBits <= NUM_COUNT_TRAILING_ZERO_BITS,
|
||||||
|
NumCountOneBits <= NUM_COUNT_ONE_BITS,
|
||||||
Eq <= BOOL_STRUCTURAL_EQ,
|
Eq <= BOOL_STRUCTURAL_EQ,
|
||||||
NotEq <= BOOL_STRUCTURAL_NOT_EQ,
|
NotEq <= BOOL_STRUCTURAL_NOT_EQ,
|
||||||
And <= BOOL_AND,
|
And <= BOOL_AND,
|
||||||
|
|
|
@ -1246,6 +1246,9 @@ define_builtins! {
|
||||||
145 NUM_MUL_CHECKED_LOWLEVEL: "mulCheckedLowlevel"
|
145 NUM_MUL_CHECKED_LOWLEVEL: "mulCheckedLowlevel"
|
||||||
146 NUM_BYTES_TO_U16_LOWLEVEL: "bytesToU16Lowlevel"
|
146 NUM_BYTES_TO_U16_LOWLEVEL: "bytesToU16Lowlevel"
|
||||||
147 NUM_BYTES_TO_U32_LOWLEVEL: "bytesToU32Lowlevel"
|
147 NUM_BYTES_TO_U32_LOWLEVEL: "bytesToU32Lowlevel"
|
||||||
|
148 NUM_COUNT_LEADING_ZERO_BITS: "countLeadingZeroBits"
|
||||||
|
149 NUM_COUNT_TRAILING_ZERO_BITS: "countTrailingZeroBits"
|
||||||
|
150 NUM_COUNT_ONE_BITS: "countOneBits"
|
||||||
}
|
}
|
||||||
4 BOOL: "Bool" => {
|
4 BOOL: "Bool" => {
|
||||||
0 BOOL_BOOL: "Bool" exposed_type=true // the Bool.Bool type alias
|
0 BOOL_BOOL: "Bool" exposed_type=true // the Bool.Bool type alias
|
||||||
|
|
|
@ -1026,11 +1026,29 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
||||||
| NumPow | NumPowInt | NumBitwiseAnd | NumBitwiseXor | NumBitwiseOr | NumShiftLeftBy
|
| NumPow | NumPowInt | NumBitwiseAnd | NumBitwiseXor | NumBitwiseOr | NumShiftLeftBy
|
||||||
| NumShiftRightBy | NumShiftRightZfBy => arena.alloc_slice_copy(&[irrelevant, irrelevant]),
|
| NumShiftRightBy | NumShiftRightZfBy => arena.alloc_slice_copy(&[irrelevant, irrelevant]),
|
||||||
|
|
||||||
NumToStr | NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumLogUnchecked
|
NumToStr
|
||||||
| NumRound | NumCeiling | NumFloor | NumToFrac | Not | NumIsFinite | NumAtan | NumAcos
|
| NumAbs
|
||||||
| NumAsin | NumIntCast | NumToIntChecked | NumToFloatCast | NumToFloatChecked => {
|
| NumNeg
|
||||||
arena.alloc_slice_copy(&[irrelevant])
|
| NumSin
|
||||||
}
|
| NumCos
|
||||||
|
| NumSqrtUnchecked
|
||||||
|
| NumLogUnchecked
|
||||||
|
| NumRound
|
||||||
|
| NumCeiling
|
||||||
|
| NumFloor
|
||||||
|
| NumToFrac
|
||||||
|
| Not
|
||||||
|
| NumIsFinite
|
||||||
|
| NumAtan
|
||||||
|
| NumAcos
|
||||||
|
| NumAsin
|
||||||
|
| NumIntCast
|
||||||
|
| NumToIntChecked
|
||||||
|
| NumToFloatCast
|
||||||
|
| NumToFloatChecked
|
||||||
|
| NumCountLeadingZeroBits
|
||||||
|
| NumCountTrailingZeroBits
|
||||||
|
| NumCountOneBits => arena.alloc_slice_copy(&[irrelevant]),
|
||||||
NumBytesToU16 => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
NumBytesToU16 => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||||
NumBytesToU32 => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
NumBytesToU32 => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||||
StrStartsWith | StrEndsWith => arena.alloc_slice_copy(&[borrowed, borrowed]),
|
StrStartsWith | StrEndsWith => arena.alloc_slice_copy(&[borrowed, borrowed]),
|
||||||
|
|
|
@ -3807,3 +3807,30 @@ fn condition_polymorphic_num_becomes_float() {
|
||||||
f32
|
f32
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
|
fn num_count_leading_zero_bits() {
|
||||||
|
assert_evals_to!(r#"Num.countLeadingZeroBits 0b0010_1000u8"#, 2, usize);
|
||||||
|
assert_evals_to!(r#"Num.countLeadingZeroBits 0b0010_1000u16"#, 10, usize);
|
||||||
|
assert_evals_to!(r#"Num.countLeadingZeroBits 0b0010_1000u32"#, 26, usize);
|
||||||
|
assert_evals_to!(r#"Num.countLeadingZeroBits 0b0010_1000u64"#, 58, usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
|
fn num_count_trailing_zero_bits() {
|
||||||
|
assert_evals_to!(r#"Num.countTrailingZeroBits 0b0010_1000u8"#, 3, usize);
|
||||||
|
assert_evals_to!(r#"Num.countTrailingZeroBits 0b0010_0000u16"#, 5, usize);
|
||||||
|
assert_evals_to!(r#"Num.countTrailingZeroBits 0u32"#, 32, usize);
|
||||||
|
assert_evals_to!(r#"Num.countTrailingZeroBits 0b0010_1111u64"#, 0, usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
|
fn num_count_one_bits() {
|
||||||
|
assert_evals_to!(r#"Num.countOneBits 0b0010_1000u8"#, 2, usize);
|
||||||
|
assert_evals_to!(r#"Num.countOneBits 0b0010_0000u16"#, 1, usize);
|
||||||
|
assert_evals_to!(r#"Num.countOneBits 0u32"#, 0, usize);
|
||||||
|
assert_evals_to!(r#"Num.countOneBits 0b0010_1111u64"#, 5, usize);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue