diff options
author | Takashi Kokubun <[email protected]> | 2023-02-13 07:30:25 -0800 |
---|---|---|
committer | Takashi Kokubun <[email protected]> | 2023-03-05 23:28:59 -0800 |
commit | 1b0fbd137fb4fa07e1a67fcf75302a80afac0c50 (patch) | |
tree | 2d8364db410e4f290fe7bcb72afea655a2570cd4 /lib/ruby_vm/mjit/insn_compiler.rb | |
parent | 9bce848b4cde9f0868dee290dfe4249421164252 (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.rb | 60 |
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 |