summaryrefslogtreecommitdiff
path: root/lib/ruby_vm/mjit/insn_compiler.rb
diff options
context:
space:
mode:
authorTakashi Kokubun <[email protected]>2023-02-13 07:30:25 -0800
committerTakashi Kokubun <[email protected]>2023-03-05 23:28:59 -0800
commit1b0fbd137fb4fa07e1a67fcf75302a80afac0c50 (patch)
tree2d8364db410e4f290fe7bcb72afea655a2570cd4 /lib/ruby_vm/mjit/insn_compiler.rb
parent9bce848b4cde9f0868dee290dfe4249421164252 (diff)
Implement branchif
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/7448
Diffstat (limited to 'lib/ruby_vm/mjit/insn_compiler.rb')
-rw-r--r--lib/ruby_vm/mjit/insn_compiler.rb60
1 files changed, 55 insertions, 5 deletions
diff --git a/lib/ruby_vm/mjit/insn_compiler.rb b/lib/ruby_vm/mjit/insn_compiler.rb
index 78b63a08e9..49f88db391 100644
--- a/lib/ruby_vm/mjit/insn_compiler.rb
+++ b/lib/ruby_vm/mjit/insn_compiler.rb
@@ -23,7 +23,7 @@ module RubyVM::MJIT
asm.incr_counter(:mjit_insns_count)
asm.comment("Insn: #{insn.name}")
- # 30/101
+ # 31/101
case insn.name
when :nop then nop(jit, ctx, asm)
# getlocal
@@ -88,7 +88,7 @@ module RubyVM::MJIT
when :leave then leave(jit, ctx, asm)
# throw
when :jump then jump(jit, ctx, asm)
- # branchif
+ when :branchif then branchif(jit, ctx, asm)
when :branchunless then branchunless(jit, ctx, asm)
# branchnil
# once
@@ -342,7 +342,7 @@ module RubyVM::MJIT
# @param asm [RubyVM::MJIT::Assembler]
def jump(jit, ctx, asm)
# Check for interrupts, but only on backward branches that may create loops
- jump_offset = jit.operand(0)
+ jump_offset = jit.operand(0, signed: true)
if jump_offset < 0
jit_check_ints(jit, ctx, asm)
end
@@ -352,14 +352,64 @@ module RubyVM::MJIT
EndBlock
end
- # branchif
+ # @param jit [RubyVM::MJIT::JITState]
+ # @param ctx [RubyVM::MJIT::Context]
+ # @param asm [RubyVM::MJIT::Assembler]
+ def branchif(jit, ctx, asm)
+ # Check for interrupts, but only on backward branches that may create loops
+ jump_offset = jit.operand(0, signed: true)
+ if jump_offset < 0
+ jit_check_ints(jit, ctx, asm)
+ end
+
+ # TODO: skip check for known truthy
+
+ # This `test` sets ZF only for Qnil and Qfalse, which let jz jump.
+ val = ctx.stack_pop
+ asm.test(val, ~Qnil)
+
+ # Set stubs
+ branch_stub = BranchStub.new(
+ iseq: jit.iseq,
+ shape: Default,
+ target0: BranchTarget.new(ctx:, pc: jit.pc + C.VALUE.size * (jit.insn.len + jump_offset)), # branch target
+ target1: BranchTarget.new(ctx:, pc: jit.pc + C.VALUE.size * jit.insn.len), # fallthrough
+ )
+ branch_stub.target0.address = Assembler.new.then do |ocb_asm|
+ @exit_compiler.compile_branch_stub(ctx, ocb_asm, branch_stub, true)
+ @ocb.write(ocb_asm)
+ end
+ branch_stub.target1.address = Assembler.new.then do |ocb_asm|
+ @exit_compiler.compile_branch_stub(ctx, ocb_asm, branch_stub, false)
+ @ocb.write(ocb_asm)
+ end
+
+ # Jump to target0 on jnz
+ branch_stub.compile = proc do |branch_asm|
+ branch_asm.comment("branchif #{branch_stub.shape}")
+ branch_asm.stub(branch_stub) do
+ case branch_stub.shape
+ in Default
+ branch_asm.jnz(branch_stub.target0.address)
+ branch_asm.jmp(branch_stub.target1.address)
+ in Next0
+ branch_asm.jz(branch_stub.target1.address)
+ in Next1
+ branch_asm.jnz(branch_stub.target0.address)
+ end
+ end
+ end
+ branch_stub.compile.call(asm)
+
+ EndBlock
+ end
# @param jit [RubyVM::MJIT::JITState]
# @param ctx [RubyVM::MJIT::Context]
# @param asm [RubyVM::MJIT::Assembler]
def branchunless(jit, ctx, asm)
# Check for interrupts, but only on backward branches that may create loops
- jump_offset = jit.operand(0)
+ jump_offset = jit.operand(0, signed: true)
if jump_offset < 0
jit_check_ints(jit, ctx, asm)
end