<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ruby.git/internal/basic_operators.h, branch v3_2_11</title>
<subtitle>The Ruby Programming Language</subtitle>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/'/>
<entry>
<title>Use a BOP for Hash#default</title>
<updated>2022-12-17T22:51:49+00:00</updated>
<author>
<name>John Hawthorn</name>
<email>john@hawthorn.email</email>
</author>
<published>2022-12-15T18:46:24+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=fbaa5db44a3b0622e2755fd00e0519a603aa9bcb'/>
<id>fbaa5db44a3b0622e2755fd00e0519a603aa9bcb</id>
<content type='text'>
On a hash miss we need to call default if it is redefined in order to
return the default value to be used. Previously we checked this with
rb_method_basic_definition_p, which avoids the method call but requires
a method lookup.

This commit replaces the previous check with BASIC_OP_UNREDEFINED_P and
a new BOP_DEFAULT. We still need to fall back to
rb_method_basic_definition_p when called on a subclasss of hash.

    |                |compare-ruby|built-ruby|
    |:---------------|-----------:|---------:|
    |hash_aref_miss  |       2.692|     3.531|
    |                |           -|     1.31x|

Co-authored-by: Daniel Colson &lt;danieljamescolson@gmail.com&gt;
Co-authored-by: "Ian C. Anderson" &lt;ian@iancanderson.com&gt;
Co-authored-by: Jack McCracken &lt;me@jackmc.xyz&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
On a hash miss we need to call default if it is redefined in order to
return the default value to be used. Previously we checked this with
rb_method_basic_definition_p, which avoids the method call but requires
a method lookup.

This commit replaces the previous check with BASIC_OP_UNREDEFINED_P and
a new BOP_DEFAULT. We still need to fall back to
rb_method_basic_definition_p when called on a subclasss of hash.

    |                |compare-ruby|built-ruby|
    |:---------------|-----------:|---------:|
    |hash_aref_miss  |       2.692|     3.531|
    |                |           -|     1.31x|

Co-authored-by: Daniel Colson &lt;danieljamescolson@gmail.com&gt;
Co-authored-by: "Ian C. Anderson" &lt;ian@iancanderson.com&gt;
Co-authored-by: Jack McCracken &lt;me@jackmc.xyz&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Fix parens on LIKELY in basic operators</title>
<updated>2022-12-12T22:05:43+00:00</updated>
<author>
<name>John Hawthorn</name>
<email>john@hawthorn.email</email>
</author>
<published>2022-12-12T19:09:10+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=43f9351177c14c554d88630b3db771b2faf11dd0'/>
<id>43f9351177c14c554d88630b3db771b2faf11dd0</id>
<content type='text'>
We want to hint to the compiler that it's likely that the BOP is
unredefined (the bit is 0). Previously we were accidentally hinting to
the compiler that it was non-zero due to a misplaced parenthesis.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
We want to hint to the compiler that it's likely that the BOP is
unredefined (the bit is 0). Previously we were accidentally hinting to
the compiler that it was non-zero due to a misplaced parenthesis.
</pre>
</div>
</content>
</entry>
<entry>
<title>Introduce BOP_CMP for optimized comparison</title>
<updated>2022-12-06T20:37:23+00:00</updated>
<author>
<name>Daniel Colson</name>
<email>danieljamescolson@gmail.com</email>
</author>
<published>2022-11-23T02:16:11+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=e69b91fae4602b69c5ef45fcf82932adde8b31d8'/>
<id>e69b91fae4602b69c5ef45fcf82932adde8b31d8</id>
<content type='text'>
Prior to this commit the `OPTIMIZED_CMP` macro relied on a method lookup
to determine whether `&lt;=&gt;` was overridden. The result of the lookup was
cached, but only for the duration of the specific method that
initialized the cmp_opt_data cache structure.

With this method lookup, `[x,y].max` is slower than doing `x &gt; y ?
x : y` even though there's an optimized instruction for "new array max".
(John noticed somebody a proposed micro-optimization based on this fact
in https://github.com/mastodon/mastodon/pull/19903.)

```rb
a, b = 1, 2
Benchmark.ips do |bm|
  bm.report('conditional') { a &gt; b ? a : b }
  bm.report('method') { [a, b].max }
  bm.compare!
end
```

Before:

```
Comparison:
         conditional: 22603733.2 i/s
              method: 19820412.7 i/s - 1.14x  (± 0.00) slower
```

This commit replaces the method lookup with a new CMP basic op, which
gives the examples above equivalent performance.

After:

```
Comparison:
              method: 24022466.5 i/s
         conditional: 23851094.2 i/s - same-ish: difference falls within
error
```

Relevant benchmarks show an improvement to Array#max and Array#min when
not using the optimized newarray_max instruction as well. They are
noticeably faster for small arrays with the relevant types, and the same
or maybe a touch faster on larger arrays.

```
$ make benchmark COMPARE_RUBY=&lt;master@5958c305&gt; ITEM=array_min
$ make benchmark COMPARE_RUBY=&lt;master@5958c305&gt; ITEM=array_max
```

The benchmarks added in this commit also look generally improved.

Co-authored-by: John Hawthorn &lt;jhawthorn@github.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Prior to this commit the `OPTIMIZED_CMP` macro relied on a method lookup
to determine whether `&lt;=&gt;` was overridden. The result of the lookup was
cached, but only for the duration of the specific method that
initialized the cmp_opt_data cache structure.

With this method lookup, `[x,y].max` is slower than doing `x &gt; y ?
x : y` even though there's an optimized instruction for "new array max".
(John noticed somebody a proposed micro-optimization based on this fact
in https://github.com/mastodon/mastodon/pull/19903.)

```rb
a, b = 1, 2
Benchmark.ips do |bm|
  bm.report('conditional') { a &gt; b ? a : b }
  bm.report('method') { [a, b].max }
  bm.compare!
end
```

Before:

```
Comparison:
         conditional: 22603733.2 i/s
              method: 19820412.7 i/s - 1.14x  (± 0.00) slower
```

This commit replaces the method lookup with a new CMP basic op, which
gives the examples above equivalent performance.

After:

```
Comparison:
              method: 24022466.5 i/s
         conditional: 23851094.2 i/s - same-ish: difference falls within
error
```

Relevant benchmarks show an improvement to Array#max and Array#min when
not using the optimized newarray_max instruction as well. They are
noticeably faster for small arrays with the relevant types, and the same
or maybe a touch faster on larger arrays.

```
$ make benchmark COMPARE_RUBY=&lt;master@5958c305&gt; ITEM=array_min
$ make benchmark COMPARE_RUBY=&lt;master@5958c305&gt; ITEM=array_max
```

The benchmarks added in this commit also look generally improved.

Co-authored-by: John Hawthorn &lt;jhawthorn@github.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Move BOP macros to separate file</title>
<updated>2022-12-06T20:37:23+00:00</updated>
<author>
<name>Daniel Colson</name>
<email>danieljamescolson@gmail.com</email>
</author>
<published>2022-12-01T01:28:14+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=c43951e60eed0b01f464cd25441b81751d2d5087'/>
<id>c43951e60eed0b01f464cd25441b81751d2d5087</id>
<content type='text'>
This commit moves ruby_basic_operators and the unredefined macros out of
vm_core.h and into basic_operators.h so that we can use them more
broadly in places where we currently use a method look up via
`rb_method_basic_definition_p` (e.g. object.c, numeric.c, complex.c,
enum.c, but also in internal/compar.h after introducing BOP_CMP and
elsewhere if we introduce more BOPs)

The most controversial part of this change is probably moving
redefined_flag out of rb_vm_t. [vm_opt_method_def_table and
vm_opt_mid_table](https://github.com/ruby/ruby/blob/9da2a5204f32a4f2ce135fddde2abb6e07d647e9/vm.c)
are not part of rb_vm_t either, and I think this fits well with those.
But more significantly it seems to result in one fewer instruction. For
example:

Before:

```
(lldb) disassemble -n vm_opt_str_freeze
miniruby`vm_exec_core:
miniruby[0x10028233e] &lt;+14558&gt;: movq   0x11a86b(%rip), %rax      ; ruby_current_vm_ptr
miniruby[0x100282345] &lt;+14565&gt;: testb  $0x4, 0x242c(%rax)
```

After:

```
(lldb) disassemble -n vm_opt_str_freeze
ruby`vm_exec_core:
ruby[0x100280ebe] &lt;+14510&gt;: testb  $0x4, 0x120147(%rip)      ; ruby_vm_redefined_flag + 43
```

Co-authored-by: John Hawthorn &lt;jhawthorn@github.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This commit moves ruby_basic_operators and the unredefined macros out of
vm_core.h and into basic_operators.h so that we can use them more
broadly in places where we currently use a method look up via
`rb_method_basic_definition_p` (e.g. object.c, numeric.c, complex.c,
enum.c, but also in internal/compar.h after introducing BOP_CMP and
elsewhere if we introduce more BOPs)

The most controversial part of this change is probably moving
redefined_flag out of rb_vm_t. [vm_opt_method_def_table and
vm_opt_mid_table](https://github.com/ruby/ruby/blob/9da2a5204f32a4f2ce135fddde2abb6e07d647e9/vm.c)
are not part of rb_vm_t either, and I think this fits well with those.
But more significantly it seems to result in one fewer instruction. For
example:

Before:

```
(lldb) disassemble -n vm_opt_str_freeze
miniruby`vm_exec_core:
miniruby[0x10028233e] &lt;+14558&gt;: movq   0x11a86b(%rip), %rax      ; ruby_current_vm_ptr
miniruby[0x100282345] &lt;+14565&gt;: testb  $0x4, 0x242c(%rax)
```

After:

```
(lldb) disassemble -n vm_opt_str_freeze
ruby`vm_exec_core:
ruby[0x100280ebe] &lt;+14510&gt;: testb  $0x4, 0x120147(%rip)      ; ruby_vm_redefined_flag + 43
```

Co-authored-by: John Hawthorn &lt;jhawthorn@github.com&gt;
</pre>
</div>
</content>
</entry>
</feed>
