Implement branchif

This commit is contained in:
Takashi Kokubun 2023-02-13 07:30:25 -08:00
parent 9bce848b4c
commit 1b0fbd137f
Notes: git 2023-03-06 07:30:05 +00:00
2 changed files with 58 additions and 7 deletions

View File

@ -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

View File

@ -12,8 +12,9 @@ module RubyVM::MJIT
Compiler.decode_insn(C.VALUE.new(pc).*)
end
def operand(index)
C.VALUE.new(pc)[index + 1]
def operand(index, signed: false)
addr = pc + (index + 1) * Fiddle::SIZEOF_VOIDP
Fiddle::Pointer.new(addr)[0, Fiddle::SIZEOF_VOIDP].unpack(signed ? 'q' : 'Q')[0]
end
def at_current_insn?