mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00

Prior to this commit the `OPTIMIZED_CMP` macro relied on a method lookup to determine whether `<=>` 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 > 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 > 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=<master@5958c305> ITEM=array_min $ make benchmark COMPARE_RUBY=<master@5958c305> ITEM=array_max ``` The benchmarks added in this commit also look generally improved. Co-authored-by: John Hawthorn <jhawthorn@github.com>
63 lines
1.4 KiB
C
63 lines
1.4 KiB
C
#ifndef INTERNAL_BOP_H /*-*-C-*-vi:se ft=c:*/
|
|
#define INTERNAL_BOP_H
|
|
|
|
#include "internal.h"
|
|
#include "ruby/internal/dllexport.h"
|
|
|
|
enum ruby_basic_operators {
|
|
BOP_PLUS,
|
|
BOP_MINUS,
|
|
BOP_MULT,
|
|
BOP_DIV,
|
|
BOP_MOD,
|
|
BOP_EQ,
|
|
BOP_EQQ,
|
|
BOP_LT,
|
|
BOP_LE,
|
|
BOP_LTLT,
|
|
BOP_AREF,
|
|
BOP_ASET,
|
|
BOP_LENGTH,
|
|
BOP_SIZE,
|
|
BOP_EMPTY_P,
|
|
BOP_NIL_P,
|
|
BOP_SUCC,
|
|
BOP_GT,
|
|
BOP_GE,
|
|
BOP_NOT,
|
|
BOP_NEQ,
|
|
BOP_MATCH,
|
|
BOP_FREEZE,
|
|
BOP_UMINUS,
|
|
BOP_MAX,
|
|
BOP_MIN,
|
|
BOP_CALL,
|
|
BOP_AND,
|
|
BOP_OR,
|
|
BOP_CMP,
|
|
|
|
BOP_LAST_
|
|
};
|
|
|
|
MJIT_SYMBOL_EXPORT_BEGIN
|
|
RUBY_EXTERN short ruby_vm_redefined_flag[BOP_LAST_];
|
|
MJIT_SYMBOL_EXPORT_END
|
|
|
|
/* optimize insn */
|
|
#define INTEGER_REDEFINED_OP_FLAG (1 << 0)
|
|
#define FLOAT_REDEFINED_OP_FLAG (1 << 1)
|
|
#define STRING_REDEFINED_OP_FLAG (1 << 2)
|
|
#define ARRAY_REDEFINED_OP_FLAG (1 << 3)
|
|
#define HASH_REDEFINED_OP_FLAG (1 << 4)
|
|
/* #define BIGNUM_REDEFINED_OP_FLAG (1 << 5) */
|
|
#define SYMBOL_REDEFINED_OP_FLAG (1 << 6)
|
|
#define TIME_REDEFINED_OP_FLAG (1 << 7)
|
|
#define REGEXP_REDEFINED_OP_FLAG (1 << 8)
|
|
#define NIL_REDEFINED_OP_FLAG (1 << 9)
|
|
#define TRUE_REDEFINED_OP_FLAG (1 << 10)
|
|
#define FALSE_REDEFINED_OP_FLAG (1 << 11)
|
|
#define PROC_REDEFINED_OP_FLAG (1 << 12)
|
|
|
|
#define BASIC_OP_UNREDEFINED_P(op, klass) (LIKELY(ruby_vm_redefined_flag[(op)]&(klass)) == 0)
|
|
|
|
#endif
|