Skip to content

Commit

Permalink
Implement the ones function for CPU and GPU integers (#975)
Browse files Browse the repository at this point in the history
  • Loading branch information
dfellis authored Nov 21, 2024
1 parent 0ead26b commit ecb31fa
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 8 deletions.
8 changes: 8 additions & 0 deletions alan/src/compile/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,14 @@ test_gpgpu!(gpu_clz => r#"
stdout "[31, 0, 0, 29]\n";
);

test_gpgpu!(gpu_ones => r#"
export fn main {
let b = GBuffer([1.i32, 2.i32, 3.i32, -1.i32]);
b.map(fn (val: gi32) = val.ones).read{i32}.print;
}"#;
stdout "[1, 1, 2, 32]\n";
);

// TODO: Fix u64 numeric constants to get u64 bitwise tests in the new test suite
test!(u64_bitwise => r#"
prefix u64 as ~ precedence 10
Expand Down
29 changes: 29 additions & 0 deletions alan/src/std/root.ln
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,8 @@ fn{Rs} wrr (a: u8, b: u8) = {Method{"rotate_right"} :: (u8, Deref{u32}) -> u8}(a
fn{Js} wrr Method{"rotateRight"} :: (u8, u8) -> u8;
fn{Rs} clz (a: u8) = {Method{"leading_zeros"} :: u8 -> u32}(a).u8;
fn{Js} clz Method{"clz"} :: u8 -> u8;
fn{Rs} ones (a: u8) = {Method{"count_ones"} :: u8 -> u32}(a).u8;
fn{Js} ones Method{"ones"} :: u8 -> u8;

fn{Rs} add Method{"wrapping_add"} :: (u16, Deref{u16}) -> u16;
fn{Js} add Method{"wrappingAdd"} :: (u16, u16) -> u16;
Expand Down Expand Up @@ -785,6 +787,8 @@ fn{Rs} wrr (a: u16, b: u16) = {Method{"rotate_right"} :: (u16, Deref{u32}) -> u1
fn{Js} wrr Method{"rotateRight"} :: (u16, u16) -> u16;
fn{Rs} clz (a: u16) = {Method{"leading_zeros"} :: u16 -> u32}(a).u16;
fn{Js} clz Method{"clz"} :: u16 -> u16;
fn{Rs} ones (a: u16) = {Method{"count_ones"} :: u16 -> u32}(a).u16;
fn{Js} ones Method{"ones"} :: u16 -> u16;

fn{Rs} add Method{"wrapping_add"} :: (u32, Deref{u32}) -> u32;
fn{Js} add Method{"wrappingAdd"} :: (u32, u32) -> u32;
Expand Down Expand Up @@ -834,6 +838,8 @@ fn{Rs} wrr (a: u32, b: u32) = {Method{"rotate_right"} :: (u32, Deref{u32}) -> u3
fn{Js} wrr Method{"rotateRight"} :: (u32, u32) -> u32;
fn{Rs} clz Method{"leading_zeros"} :: u32 -> u32;
fn{Js} clz Method{"clz"} :: u32 -> u32;
fn{Rs} ones (a: u32) = {Method{"count_ones"} :: u32 -> u32}(a).u32;
fn{Js} ones Method{"ones"} :: u32 -> u32;

fn{Rs} add Method{"wrapping_add"} :: (u64, Deref{u64}) -> u64;
fn{Js} add Method{"wrappingAdd"} :: (u64, u64) -> u64;
Expand Down Expand Up @@ -883,6 +889,8 @@ fn{Rs} wrr (a: u64, b: u64) = {Method{"rotate_right"} :: (u64, Deref{u32}) -> u6
fn{Js} wrr Method{"rotateRight"} :: (u64, u64) -> u64;
fn{Rs} clz (a: u64) = {Method{"leading_zeros"} :: u64 -> u32}(a).u64;
fn{Js} clz Method{"clz"} :: u64 -> u64;
fn{Rs} ones (a: u64) = {Method{"count_ones"} :: u64 -> u32}(a).u64;
fn{Js} ones Method{"ones"} :: u64 -> u64;

/// Signed Integer-related functions and function bindings
fn{Rs} add Method{"wrapping_add"} :: (i8, Deref{i8}) -> i8;
Expand Down Expand Up @@ -937,6 +945,8 @@ fn{Rs} wrr (a: i8, b: i8) = {Method{"rotate_right"} :: (i8, Deref{u32}) -> i8}(a
fn{Js} wrr Method{"rotateRight"} :: (i8, i8) -> i8;
fn{Rs} clz (a: i8) = {Method{"leading_zeros"} :: i8 -> u32}(a).i8;
fn{Js} clz Method{"clz"} :: i8 -> i8;
fn{Rs} ones (a: i8) = {Method{"count_ones"} :: i8 -> u32}(a).i8;
fn{Js} ones Method{"ones"} :: i8 -> i8;

fn{Rs} add Method{"wrapping_add"} :: (i16, Deref{i16}) -> i16;
fn{Js} add Method{"wrappingAdd"} :: (i16, i16) -> i16;
Expand Down Expand Up @@ -990,6 +1000,8 @@ fn{Rs} wrr (a: i16, b: i16) = {Method{"rotate_right"} :: (i16, Deref{u32}) -> i1
fn{Js} wrr Method{"rotateRight"} :: (i16, i16) -> i16;
fn{Rs} clz (a: i16) = {Method{"leading_zeros"} :: i16 -> u32}(a).i16;
fn{Js} clz Method{"clz"} :: i16 -> i16;
fn{Rs} ones (a: i16) = {Method{"count_ones"} :: i16 -> u32}(a).i16;
fn{Js} ones Method{"ones"} :: i16 -> i16;

fn{Rs} add Method{"wrapping_add"} :: (i32, Deref{i32}) -> i32;
fn{Js} add Method{"wrappingAdd"} :: (i32, i32) -> i32;
Expand Down Expand Up @@ -1043,6 +1055,8 @@ fn{Rs} wrr (a: i32, b: i32) = {Method{"rotate_right"} :: (i32, Deref{u32}) -> i3
fn{Js} wrr Method{"rotateRight"} :: (i32, i32) -> i32;
fn{Rs} clz (a: i32) = {Method{"leading_zeros"} :: i32 -> u32}(a).i32;
fn{Js} clz Method{"clz"} :: i32 -> i32;
fn{Rs} ones (a: i32) = {Method{"count_ones"} :: i32 -> u32}(a).i32;
fn{Js} ones Method{"ones"} :: i32 -> i32;

fn{Rs} add Method{"wrapping_add"} :: (i64, Deref{i64}) -> i64;
fn{Js} add Method{"wrappingAdd"} :: (i64, i64) -> i64;
Expand Down Expand Up @@ -1096,6 +1110,8 @@ fn{Rs} wrr (a: i64, b: i64) = {Method{"rotate_right"} :: (i64, Deref{u32}) -> i6
fn{Js} wrr Method{"rotateRight"} :: (i64, i64) -> i64;
fn{Rs} clz (a: i64) = {Method{"leading_zeros"} :: i64 -> u32}(a).i64;
fn{Js} clz Method{"clz"} :: i64 -> i64;
fn{Rs} ones (a: i64) = {Method{"count_ones"} :: i64 -> u32}(a).i64;
fn{Js} ones Method{"ones"} :: i64 -> i64;

/// String related bindings
fn{Rs} string "format!" :: ("{}", f32) -> string;
Expand Down Expand Up @@ -3676,6 +3692,19 @@ fn clz(v: gvec3u) = gclz{gvec3u}(v);
fn clz(v: gvec4i) = gclz{gvec4i}(v);
fn clz(v: gvec4u) = gclz{gvec4u}(v);

fn gones{I}(v: I) {
let varName = 'countOneBits('.concat(v.varName).concat(')');
return {I}(varName, v.statements, v.buffers);
}
fn ones(v: gi32) = gones{gi32}(v);
fn ones(v: gu32) = gones{gu32}(v);
fn ones(v: gvec2i) = gones{gvec2i}(v);
fn ones(v: gvec2u) = gones{gvec2u}(v);
fn ones(v: gvec3i) = gones{gvec3i}(v);
fn ones(v: gvec3u) = gones{gvec3u}(v);
fn ones(v: gvec4i) = gones{gvec4i}(v);
fn ones(v: gvec4u) = gones{gvec4u}(v);

fn gadd{A, B}(a: A, b: B) {
let varName = '('.concat(a.varName).concat(' + ').concat(b.varName).concat(')');
let statements = a.statements.concat(b.statements);
Expand Down
56 changes: 48 additions & 8 deletions alan/test.ln
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,12 @@ export fn{Test} main {
.assert(eq, 0.i8.clz, 8.i8)
.assert(eq, 1.i8.clz, 7.i8)
.assert(eq, 2.i8.clz, 6.i8)
.assert(eq, (-128).i8.clz, 0.i8));
.assert(eq, (-128).i8.clz, 0.i8))
.it("ones", fn (test: Mut{Testing}) = test
.assert(eq, 1.i8.ones, 1.i8)
.assert(eq, 2.i8.ones, 1.i8)
.assert(eq, 3.i8.ones, 2.i8)
.assert(eq, (-1).i8.ones, 8.i8));

test.describe("Basic math tests i16")
.it("add")
Expand All @@ -88,7 +93,12 @@ export fn{Test} main {
.assert(eq, 0.i16.clz, 16.i16)
.assert(eq, 1.i16.clz, 15.i16)
.assert(eq, 2.i16.clz, 14.i16)
.assert(eq, (-32768).i16.clz, 0.i16));
.assert(eq, (-32768).i16.clz, 0.i16))
.it("ones", fn (test: Mut{Testing}) = test
.assert(eq, 1.i16.ones, 1.i16)
.assert(eq, 2.i16.ones, 1.i16)
.assert(eq, 3.i16.ones, 2.i16)
.assert(eq, (-1).i16.ones, 16.i16));

test.describe("Basic math tests i32")
.it("add")
Expand All @@ -115,7 +125,12 @@ export fn{Test} main {
.assert(eq, 0.i32.clz, 32.i32)
.assert(eq, 1.i32.clz, 31.i32)
.assert(eq, 2.i32.clz, 30.i32)
.assert(eq, (-2_147_483_648).i32.clz, 0.i32));
.assert(eq, (-2_147_483_648).i32.clz, 0.i32))
.it("ones", fn (test: Mut{Testing}) = test
.assert(eq, 1.i32.ones, 1.i32)
.assert(eq, 2.i32.ones, 1.i32)
.assert(eq, 3.i32.ones, 2.i32)
.assert(eq, (-1).i32.ones, 32.i32));

test.describe("Basic math tests i64")
.it("add")
Expand All @@ -142,7 +157,12 @@ export fn{Test} main {
.assert(eq, 0.clz, 64.i64)
.assert(eq, 1.clz, 63.i64)
.assert(eq, 2.i64.clz, 62.i64)
.assert(eq, -9_223_372_036_854_775_808.clz, 0));
.assert(eq, -9_223_372_036_854_775_808.clz, 0))
.it("ones", fn (test: Mut{Testing}) = test
.assert(eq, 1.ones, 1)
.assert(eq, 2.ones, 1)
.assert(eq, 3.ones, 2)
.assert(eq, -1.ones, 64));

test.describe("Basic math tests u8")
.it("add")
Expand All @@ -165,7 +185,12 @@ export fn{Test} main {
.assert(eq, 0.u8.clz, 8.u8)
.assert(eq, 1.u8.clz, 7.u8)
.assert(eq, 2.u8.clz, 6.u8)
.assert(eq, 255.u8.clz, 0.u8));
.assert(eq, 255.u8.clz, 0.u8))
.it("ones", fn (test: Mut{Testing}) = test
.assert(eq, 1.u8.ones, 1.u8)
.assert(eq, 2.u8.ones, 1.u8)
.assert(eq, 3.u8.ones, 2.u8)
.assert(eq, 255.u8.ones, 8.u8));

test.describe("Basic math tests u16")
.it("add")
Expand All @@ -188,7 +213,12 @@ export fn{Test} main {
.assert(eq, 0.u16.clz, 16.u16)
.assert(eq, 1.u16.clz, 15.u16)
.assert(eq, 2.u16.clz, 14.u16)
.assert(eq, 65535.u16.clz, 0.u16));
.assert(eq, 65535.u16.clz, 0.u16))
.it("ones", fn (test: Mut{Testing}) = test
.assert(eq, 1.u16.ones, 1.u16)
.assert(eq, 2.u16.ones, 1.u16)
.assert(eq, 3.u16.ones, 2.u16)
.assert(eq, 65535.u16.ones, 16.u16));

test.describe("Basic math tests u32")
.it("add")
Expand All @@ -211,7 +241,12 @@ export fn{Test} main {
.assert(eq, 0.u32.clz, 32.u32)
.assert(eq, 1.u32.clz, 31.u32)
.assert(eq, 2.u32.clz, 30.u32)
.assert(eq, 2_147_483_648.u32.clz, 0.u32));
.assert(eq, 2_147_483_648.u32.clz, 0.u32))
.it("ones", fn (test: Mut{Testing}) = test
.assert(eq, 1.u32.ones, 1.u32)
.assert(eq, 2.u32.ones, 1.u32)
.assert(eq, 3.u32.ones, 2.u32)
.assert(eq, 4_294_967_295.u32.ones, 32.u32));

test.describe("Basic math tests u64")
.it("add")
Expand All @@ -233,8 +268,13 @@ export fn{Test} main {
.it("clz", fn (test: Mut{Testing}) = test
.assert(eq, 0.u64.clz, 64.u64)
.assert(eq, 1.u64.clz, 63.u64)
.assert(eq, 2.u64.clz, 62.u64));
.assert(eq, 2.u64.clz, 62.u64))
// .assert(eq, 9_223_372_036_854_775_808.u64.clz, 0.u64)); TODO: Fix u64 representation
.it("ones", fn (test: Mut{Testing}) = test
.assert(eq, 1.u64.ones, 1.u64)
.assert(eq, 2.u64.ones, 1.u64)
.assert(eq, 3.u64.ones, 2.u64));
// .assert(eq, 9_223_372_036_854_775_808.ones, 64.u32)); TODO: Same u64 representation issue

test.describe("Basic math tests f32")
.it("add")
Expand Down

0 comments on commit ecb31fa

Please sign in to comment.