Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/zjit-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
specopts: '-T --zjit-disable-hir-opt -T --zjit-call-threshold=1'
configure: '--enable-zjit=dev'

- test_task: 'zjit-check' # zjit-test + quick feedback of test_zjit.rb
- test_task: 'zjit-check' # zjit-test + quick feedback of test_zjit_cli.rb
configure: '--enable-yjit=dev --enable-zjit'
rust_version: "1.85.0"

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/zjit-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ jobs:
configure: '--enable-zjit=dev'
run_opts: '--zjit-inline-threshold=0 --zjit-call-threshold=1'

- test_task: 'zjit-check' # zjit-test + quick feedback of test_zjit.rb
- test_task: 'zjit-check' # zjit-test + quick feedback of test_zjit_cli.rb
configure: '--enable-yjit --enable-zjit=dev'
rust_version: '1.85.0'

Expand Down
17 changes: 17 additions & 0 deletions bignum.c
Original file line number Diff line number Diff line change
Expand Up @@ -7029,6 +7029,23 @@ rb_big_bit_length(VALUE big)
INTEGER_PACK_LSWORD_FIRST|INTEGER_PACK_NATIVE_BYTE_ORDER);
}

VALUE
rb_big_bit_count(VALUE big)
{
if (BIGNUM_NEGATIVE_P(big))
rb_raise(rb_eArgError, "bit_count is undefined for negative integers");

BDIGIT *ds = BDIGITS(big);
size_t n = BIGNUM_LEN(big);
size_t count = 0;

while (n--) {
count += rb_popcount64((uint64_t)ds[n]);
}

return SIZET2NUM(count);
}

VALUE
rb_big_odd_p(VALUE num)
{
Expand Down
24 changes: 12 additions & 12 deletions doc/jit/zjit.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,28 +287,28 @@ cd zjit && cargo insta review

Test changes will be reviewed alongside code changes.

### Running integration tests
### Running smoke tests

This command runs Ruby execution tests.
Runs both `make zjit-test` and `test/ruby/test_zjit_cli.rb`:

```bash
make test-all TESTS="test/ruby/test_zjit.rb"
```

You can also run a single test case by matching the method name:

```bash
make test-all TESTS="test/ruby/test_zjit.rb -n TestZJIT#test_putobject"
make zjit-check
```

### Running all tests
### Integration testing

Runs both `make zjit-test` and `test/ruby/test_zjit.rb`:
A thorough test run will want to enable ZJIT on Ruby workloads. Some
test suites written in Ruby in this repository accepts the `RUN_OPTS`
Make macro for passing ruby(1) command-line arguments:

```bash
make zjit-check
make test-all RUN_OPTS='--zjit-call-threshold=2'
make btest RUN_OPTS='--zjit-call-threshold=1'
```

See [Testing Ruby](rdoc-ref:contributing/testing_ruby.md) for a list of
test suites.

## Statistics Collection

ZJIT provides detailed statistics about JIT compilation and execution behavior.
Expand Down
13 changes: 0 additions & 13 deletions include/ruby/internal/intern/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,19 +174,6 @@ VALUE rb_mod_include_p(VALUE child, VALUE parent);
*/
VALUE rb_mod_ancestors(VALUE mod);

/**
* Queries the class's descendants. This routine gathers classes that are
* subclasses of the given class (or subclasses of those subclasses, etc.),
* returning an array of classes that have the given class as an ancestor.
* The returned array does not include the given class or singleton classes.
*
* @param[in] klass A class.
* @return An array of classes where `klass` is an ancestor.
*
* @internal
*/
VALUE rb_class_descendants(VALUE klass);

/**
* Queries the class's direct descendants. This routine gathers classes that are
* direct subclasses of the given class,
Expand Down
1 change: 1 addition & 0 deletions internal/bignum.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ VALUE rb_big_aref2(VALUE num, VALUE beg, VALUE len);
VALUE rb_big_abs(VALUE x);
VALUE rb_big_size_m(VALUE big);
VALUE rb_big_bit_length(VALUE big);
VALUE rb_big_bit_count(VALUE big);
VALUE rb_big_remainder(VALUE x, VALUE y);
VALUE rb_big_gt(VALUE x, VALUE y);
VALUE rb_big_ge(VALUE x, VALUE y);
Expand Down
1 change: 1 addition & 0 deletions internal/numeric.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ VALUE rb_int_even_p(VALUE num);
VALUE rb_int_odd_p(VALUE num);
VALUE rb_int_abs(VALUE num);
VALUE rb_int_bit_length(VALUE num);
VALUE rb_int_bit_count(VALUE num);
VALUE rb_int_uminus(VALUE num);
VALUE rb_int_comp(VALUE num);

Expand Down
44 changes: 44 additions & 0 deletions numeric.c
Original file line number Diff line number Diff line change
Expand Up @@ -5732,6 +5732,49 @@ rb_int_bit_length(VALUE num)
return Qnil;
}

static VALUE
rb_fix_bit_count(VALUE fix)
{
long v = FIX2LONG(fix);
if (v < 0)
rb_raise(rb_eArgError, "bit_count is undefined for negative integers");
return LONG2FIX(rb_popcount_intptr((uintptr_t)v));
}

/*
* call-seq:
* bit_count -> integer
*
* Returns the number of set bits (bits equal to 1) in the binary
* representation of +self+, also known as the population count or
* Hamming weight.
*
* 0.bit_count # => 0
* 1.bit_count # => 1
* 7.bit_count # => 3
* 0b10101.bit_count # => 3
* 255.bit_count # => 8
* (2**1000).bit_count # => 1
* (2**1000-1).bit_count # => 1000
*
* Raises an exception if +self+ is negative.
*
* (-1).bit_count # Raises ArgumentError
*
*/

VALUE
rb_int_bit_count(VALUE num)
{
if (FIXNUM_P(num)) {
return rb_fix_bit_count(num);
}
else if (RB_BIGNUM_TYPE_P(num)) {
return rb_big_bit_count(num);
}
UNREACHABLE_RETURN(Qnil);
}

static VALUE
rb_fix_digits(VALUE fix, long base)
{
Expand Down Expand Up @@ -6610,6 +6653,7 @@ Init_Numeric(void)
rb_define_method(rb_cInteger, ">>", rb_int_rshift, 1);

rb_define_method(rb_cInteger, "digits", rb_int_digits, -1);
rb_define_method(rb_cInteger, "bit_count", rb_int_bit_count, 0);

#define fix_to_s_static(n) do { \
VALUE lit = rb_fstring_literal(#n); \
Expand Down
31 changes: 31 additions & 0 deletions spec/ruby/core/integer/bit_count_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
require_relative '../../spec_helper'

ruby_version_is "4.1" do
describe "Integer#bit_count" do
it "returns the number of set bits in the binary representation" do
0.bit_count.should == 0
1.bit_count.should == 1
2.bit_count.should == 1
3.bit_count.should == 2
7.bit_count.should == 3
0b10101.bit_count.should == 3
0xff.bit_count.should == 8
0x100.bit_count.should == 1
fixnum_max.bit_count.should == fixnum_max.to_s(2).count("1")

(2**1000).bit_count.should == 1
(2**1000 - 1).bit_count.should == 1000
(2**1000 + 2**500).bit_count.should == 2
(2**64 - 1).bit_count.should == 64
(2**10000 - 1).bit_count.should == 10000
end

it "raises an ArgumentError for a negative number" do
-> { -1.bit_count }.should raise_error(ArgumentError)
-> { -19.bit_count }.should raise_error(ArgumentError)
-> { fixnum_min.bit_count }.should raise_error(ArgumentError)
-> { (-2**1000).bit_count }.should raise_error(ArgumentError)
-> { (-2**1000 - 1).bit_count }.should raise_error(ArgumentError)
end
end
end
35 changes: 35 additions & 0 deletions test/ruby/test_integer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,41 @@ def test_bit_length
}
end

def test_bit_count
assert_equal(0, 0.bit_count)
assert_equal(1, 1.bit_count)
assert_equal(1, 2.bit_count)
assert_equal(2, 3.bit_count)
assert_equal(3, 7.bit_count)
assert_equal(3, 0b10101.bit_count)
assert_equal(8, 0xff.bit_count)
assert_equal(1, 0x100.bit_count)

# Fixnum boundaries
assert_equal(1, (2**30).bit_count)
assert_equal(1, (2**62).bit_count)

# Bignum
assert_equal(1, (2**64).bit_count)
assert_equal(64, (2**64-1).bit_count)
assert_equal(1, (2**1000).bit_count)
assert_equal(1000, (2**1000-1).bit_count)
assert_equal(2, (2**1000 + 2**500).bit_count)

0.upto(1000) {|i|
n = 2**i
assert_equal(1, n.bit_count, "(#{n}).bit_count")
assert_equal(i, (n-1).bit_count, "(#{n-1}).bit_count")
assert_equal(2, (n+1).bit_count, "(#{n+1}).bit_count") if i >= 1
}
end

def test_bit_count_for_negative_numbers
assert_raise(ArgumentError) { -1.bit_count }
assert_raise(ArgumentError) { -19.bit_count }
assert_raise(ArgumentError) { (-2**1000).bit_count }
end

def test_digits
assert_equal([0], 0.digits)
assert_equal([1], 1.digits)
Expand Down
Loading