summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compile.c2
-rw-r--r--defs/id.def2
-rw-r--r--insns.def28
-rw-r--r--test/ruby/test_jit.rb8
-rw-r--r--test/ruby/test_optimization.rb10
-rw-r--r--tool/transform_mjit_header.rb2
-rw-r--r--vm.c2
-rw-r--r--vm_core.h2
-rw-r--r--vm_insnhelper.c24
9 files changed, 80 insertions, 0 deletions
diff --git a/compile.c b/compile.c
index 83d992a2e9..0a2e076b39 100644
--- a/compile.c
+++ b/compile.c
@@ -3245,6 +3245,8 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
case idGE: SP_INSN(ge); return COMPILE_OK;
case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
case idAREF: SP_INSN(aref); return COMPILE_OK;
+ case idAnd: SP_INSN(and); return COMPILE_OK;
+ case idOr: SP_INSN(or); return COMPILE_OK;
}
break;
case 2:
diff --git a/defs/id.def b/defs/id.def
index e1a66f5030..fe61d254c9 100644
--- a/defs/id.def
+++ b/defs/id.def
@@ -97,6 +97,8 @@ token_ops = %[\
Eqq === EQQ
Neq != NEQ
Not !
+ And &
+ Or |
Backquote `
EqTilde =~ MATCH
NeqTilde !~ NMATCH
diff --git a/insns.def b/insns.def
index 742cd87960..cacc5b709f 100644
--- a/insns.def
+++ b/insns.def
@@ -1216,6 +1216,34 @@ opt_ltlt
}
}
+/* optimized X&Y. */
+DEFINE_INSN
+opt_and
+(CALL_INFO ci, CALL_CACHE cc)
+(VALUE recv, VALUE obj)
+(VALUE val)
+{
+ val = vm_opt_and(recv, obj);
+
+ if (val == Qundef) {
+ CALL_SIMPLE_METHOD();
+ }
+}
+
+/* optimized X|Y. */
+DEFINE_INSN
+opt_or
+(CALL_INFO ci, CALL_CACHE cc)
+(VALUE recv, VALUE obj)
+(VALUE val)
+{
+ val = vm_opt_or(recv, obj);
+
+ if (val == Qundef) {
+ CALL_SIMPLE_METHOD();
+ }
+}
+
/* [] */
DEFINE_INSN
opt_aref
diff --git a/test/ruby/test_jit.rb b/test/ruby/test_jit.rb
index 50f318c2a7..3770faf038 100644
--- a/test/ruby/test_jit.rb
+++ b/test/ruby/test_jit.rb
@@ -478,6 +478,14 @@ class TestJIT < Test::Unit::TestCase
assert_compile_once('[1] << 2', result_inspect: '[1, 2]', insns: %i[opt_ltlt])
end
+ def test_compile_insn_opt_and
+ assert_compile_once('1 & 3', result_inspect: '1', insns: %i[opt_and])
+ end
+
+ def test_compile_insn_opt_or
+ assert_compile_once('1 | 3', result_inspect: '3', insns: %i[opt_or])
+ end
+
def test_compile_insn_opt_aref
skip_on_mswin
# optimized call (optimized JIT) -> send call
diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb
index d4a1fdbcea..c425254661 100644
--- a/test/ruby/test_optimization.rb
+++ b/test/ruby/test_optimization.rb
@@ -187,6 +187,16 @@ class TestRubyOptimization < Test::Unit::TestCase
assert_redefine_method('String', '<<', 'assert_equal "b", "a" << "b"')
end
+ def test_fixnum_and
+ assert_equal 1, 1&3
+ assert_redefine_method('Integer', '&', 'assert_equal 3, 1&3')
+ end
+
+ def test_fixnum_or
+ assert_equal 3, 1|3
+ assert_redefine_method('Integer', '|', 'assert_equal 1, 3|1')
+ end
+
def test_array_plus
assert_equal [1,2], [1]+[2]
assert_redefine_method('Array', '+', 'assert_equal [2], [1]+[2]')
diff --git a/tool/transform_mjit_header.rb b/tool/transform_mjit_header.rb
index 936a0e1945..1000172352 100644
--- a/tool/transform_mjit_header.rb
+++ b/tool/transform_mjit_header.rb
@@ -52,6 +52,8 @@ module MJITHeader
'vm_opt_gt',
'vm_opt_ge',
'vm_opt_ltlt',
+ 'vm_opt_and',
+ 'vm_opt_or',
'vm_opt_aref',
'vm_opt_aset',
'vm_opt_aref_with',
diff --git a/vm.c b/vm.c
index da9afe2fc7..eb47a83d5f 100644
--- a/vm.c
+++ b/vm.c
@@ -1610,6 +1610,8 @@ vm_init_redefined_flag(void)
OP(Max, MAX), (C(Array));
OP(Min, MIN), (C(Array));
OP(Call, CALL), (C(Proc));
+ OP(And, AND), (C(Integer));
+ OP(Or, OR), (C(Integer));
#undef C
#undef OP
}
diff --git a/vm_core.h b/vm_core.h
index bb6409719b..1ab49b05de 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -531,6 +531,8 @@ enum ruby_basic_operators {
BOP_MAX,
BOP_MIN,
BOP_CALL,
+ BOP_AND,
+ BOP_OR,
BOP_LAST_
};
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 29b935803b..29e6545398 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -3653,6 +3653,30 @@ vm_opt_ltlt(VALUE recv, VALUE obj)
}
static VALUE
+vm_opt_and(VALUE recv, VALUE obj)
+{
+ if (FIXNUM_2_P(recv, obj) &&
+ BASIC_OP_UNREDEFINED_P(BOP_AND, INTEGER_REDEFINED_OP_FLAG)) {
+ return LONG2NUM(FIX2LONG(recv) & FIX2LONG(obj));
+ }
+ else {
+ return Qundef;
+ }
+}
+
+static VALUE
+vm_opt_or(VALUE recv, VALUE obj)
+{
+ if (FIXNUM_2_P(recv, obj) &&
+ BASIC_OP_UNREDEFINED_P(BOP_OR, INTEGER_REDEFINED_OP_FLAG)) {
+ return LONG2NUM(FIX2LONG(recv) | FIX2LONG(obj));
+ }
+ else {
+ return Qundef;
+ }
+}
+
+static VALUE
vm_opt_aref(VALUE recv, VALUE obj)
{
if (SPECIAL_CONST_P(recv)) {