Support SP motion in all insns

This commit is contained in:
Takashi Kokubun 2023-02-08 09:30:47 -08:00
parent d332c6ee12
commit 6be4e065eb
3 changed files with 49 additions and 48 deletions

View File

@ -8,3 +8,9 @@ assert_equal 'true', %q{
lt(1, 2) lt(1, 2)
lt('a', 'b') lt('a', 'b')
} }
assert_equal '3', %q{
def foo = 2
def bar = 1 + foo + nil.to_i
bar
}

View File

@ -175,20 +175,16 @@ module RubyVM::MJIT
# @param ctx [RubyVM::MJIT::Context] # @param ctx [RubyVM::MJIT::Context]
# @param asm [RubyVM::MJIT::Assembler] # @param asm [RubyVM::MJIT::Assembler]
def putnil(jit, ctx, asm) def putnil(jit, ctx, asm)
assert_equal(ctx.sp_offset, ctx.stack_size) # TODO: support SP motion putobject(jit, ctx, asm, val: Qnil)
asm.mov([SP, C.VALUE.size * ctx.stack_size], Qnil)
ctx.stack_push(1)
KeepCompiling
end end
# @param jit [RubyVM::MJIT::JITState] # @param jit [RubyVM::MJIT::JITState]
# @param ctx [RubyVM::MJIT::Context] # @param ctx [RubyVM::MJIT::Context]
# @param asm [RubyVM::MJIT::Assembler] # @param asm [RubyVM::MJIT::Assembler]
def putself(jit, ctx, asm) def putself(jit, ctx, asm)
assert_equal(ctx.sp_offset, ctx.stack_size) # TODO: support SP motion stack_top = ctx.stack_push
asm.mov(:rax, [CFP, C.rb_control_frame_t.offsetof(:self)]) asm.mov(:rax, [CFP, C.rb_control_frame_t.offsetof(:self)])
asm.mov([SP, C.VALUE.size * ctx.stack_size], :rax) asm.mov(stack_top, :rax)
ctx.stack_push(1)
KeepCompiling KeepCompiling
end end
@ -197,16 +193,15 @@ module RubyVM::MJIT
# @param asm [RubyVM::MJIT::Assembler] # @param asm [RubyVM::MJIT::Assembler]
def putobject(jit, ctx, asm, val: jit.operand(0)) def putobject(jit, ctx, asm, val: jit.operand(0))
# Push it to the stack # Push it to the stack
# TODO: GC offsets stack_top = ctx.stack_push
assert_equal(ctx.sp_offset, ctx.stack_size) # TODO: support SP motion
if asm.imm32?(val) if asm.imm32?(val)
asm.mov([SP, C.VALUE.size * ctx.stack_size], val) asm.mov(stack_top, val)
else # 64-bit immediates can't be directly written to memory else # 64-bit immediates can't be directly written to memory
asm.mov(:rax, val) asm.mov(:rax, val)
asm.mov([SP, C.VALUE.size * ctx.stack_size], :rax) asm.mov(stack_top, :rax)
end end
# TODO: GC offsets?
ctx.stack_push(1)
KeepCompiling KeepCompiling
end end
@ -397,35 +392,37 @@ module RubyVM::MJIT
return EndBlock return EndBlock
end end
assert_equal(ctx.sp_offset, ctx.stack_size) # TODO: support SP motion
comptime_recv = jit.peek_at_stack(1) comptime_recv = jit.peek_at_stack(1)
comptime_obj = jit.peek_at_stack(0) comptime_obj = jit.peek_at_stack(0)
if fixnum?(comptime_recv) && fixnum?(comptime_obj) if fixnum?(comptime_recv) && fixnum?(comptime_obj)
# Generate a side exit before popping operands
side_exit = side_exit(jit, ctx)
unless @invariants.assume_bop_not_redefined(jit, C.INTEGER_REDEFINED_OP_FLAG, C.BOP_MINUS) unless @invariants.assume_bop_not_redefined(jit, C.INTEGER_REDEFINED_OP_FLAG, C.BOP_MINUS)
return CantCompile return CantCompile
end end
assert_equal(ctx.sp_offset, ctx.stack_size) # TODO: support SP motion obj_opnd = ctx.stack_pop
recv_index = ctx.stack_size - 2 recv_opnd = ctx.stack_pop
obj_index = ctx.stack_size - 1
asm.comment('guard recv is fixnum') # TODO: skip this with type information asm.comment('guard recv is fixnum') # TODO: skip this with type information
asm.test([SP, C.VALUE.size * recv_index], C.RUBY_FIXNUM_FLAG) asm.test(recv_opnd, C.RUBY_FIXNUM_FLAG)
asm.jz(side_exit(jit, ctx)) asm.jz(side_exit)
asm.comment('guard obj is fixnum') # TODO: skip this with type information asm.comment('guard obj is fixnum') # TODO: skip this with type information
asm.test([SP, C.VALUE.size * obj_index], C.RUBY_FIXNUM_FLAG) asm.test(obj_opnd, C.RUBY_FIXNUM_FLAG)
asm.jz(side_exit(jit, ctx)) asm.jz(side_exit)
asm.mov(:rax, [SP, C.VALUE.size * recv_index]) asm.mov(:rax, recv_opnd)
asm.mov(:rcx, [SP, C.VALUE.size * obj_index]) asm.mov(:rcx, obj_opnd)
asm.sub(:rax, :rcx) asm.sub(:rax, :rcx)
asm.jo(side_exit(jit, ctx)) asm.jo(side_exit)
asm.add(:rax, 1) # re-tag asm.add(:rax, 1) # re-tag
asm.mov([SP, C.VALUE.size * recv_index], :rax)
ctx.stack_pop(1) dst_opnd = ctx.stack_push
asm.mov(dst_opnd, :rax)
KeepCompiling KeepCompiling
else else
CantCompile # TODO: delegate to send CantCompile # TODO: delegate to send
@ -447,35 +444,37 @@ module RubyVM::MJIT
return EndBlock return EndBlock
end end
assert_equal(ctx.sp_offset, ctx.stack_size) # TODO: support SP motion
comptime_recv = jit.peek_at_stack(1) comptime_recv = jit.peek_at_stack(1)
comptime_obj = jit.peek_at_stack(0) comptime_obj = jit.peek_at_stack(0)
if fixnum?(comptime_recv) && fixnum?(comptime_obj) if fixnum?(comptime_recv) && fixnum?(comptime_obj)
# Generate a side exit before popping operands
side_exit = side_exit(jit, ctx)
unless @invariants.assume_bop_not_redefined(jit, C.INTEGER_REDEFINED_OP_FLAG, C.BOP_LT) unless @invariants.assume_bop_not_redefined(jit, C.INTEGER_REDEFINED_OP_FLAG, C.BOP_LT)
return CantCompile return CantCompile
end end
assert_equal(ctx.sp_offset, ctx.stack_size) # TODO: support SP motion obj_opnd = ctx.stack_pop
recv_index = ctx.stack_size - 2 recv_opnd = ctx.stack_pop
obj_index = ctx.stack_size - 1
asm.comment('guard recv is fixnum') # TODO: skip this with type information asm.comment('guard recv is fixnum') # TODO: skip this with type information
asm.test([SP, C.VALUE.size * recv_index], C.RUBY_FIXNUM_FLAG) asm.test(recv_opnd, C.RUBY_FIXNUM_FLAG)
asm.jz(side_exit(jit, ctx)) asm.jz(side_exit)
asm.comment('guard obj is fixnum') # TODO: skip this with type information asm.comment('guard obj is fixnum') # TODO: skip this with type information
asm.test([SP, C.VALUE.size * obj_index], C.RUBY_FIXNUM_FLAG) asm.test(obj_opnd, C.RUBY_FIXNUM_FLAG)
asm.jz(side_exit(jit, ctx)) asm.jz(side_exit)
asm.mov(:rax, [SP, C.VALUE.size * obj_index]) asm.mov(:rax, obj_opnd)
asm.cmp([SP, C.VALUE.size * recv_index], :rax) asm.cmp(recv_opnd, :rax)
asm.mov(:rax, Qfalse) asm.mov(:rax, Qfalse)
asm.mov(:rcx, Qtrue) asm.mov(:rcx, Qtrue)
asm.cmovl(:rax, :rcx) asm.cmovl(:rax, :rcx)
asm.mov([SP, C.VALUE.size * recv_index], :rax)
ctx.stack_pop(1) dst_opnd = ctx.stack_push
asm.mov(dst_opnd, :rax)
KeepCompiling KeepCompiling
else else
CantCompile # TODO: delegate to send CantCompile # TODO: delegate to send
@ -725,18 +724,16 @@ module RubyVM::MJIT
asm.incr_counter(:send_kw_splat) asm.incr_counter(:send_kw_splat)
return CantCompile return CantCompile
end end
assert_equal(ctx.sp_offset, ctx.stack_size) # TODO: support SP motion recv_index = argc + ((flags & C.VM_CALL_ARGS_BLOCKARG == 0) ? 0 : 1)
recv_depth = argc + ((flags & C.VM_CALL_ARGS_BLOCKARG == 0) ? 0 : 1)
recv_index = ctx.stack_size - 1 - recv_depth
comptime_recv = jit.peek_at_stack(recv_depth) comptime_recv = jit.peek_at_stack(recv_index)
comptime_recv_klass = C.rb_class_of(comptime_recv) comptime_recv_klass = C.rb_class_of(comptime_recv)
# Guard the receiver class (part of vm_search_method_fastpath) # Guard the receiver class (part of vm_search_method_fastpath)
if comptime_recv_klass.singleton_class? if comptime_recv_klass.singleton_class?
asm.comment('guard known object with singleton class') asm.comment('guard known object with singleton class')
asm.mov(:rax, C.to_value(comptime_recv)) asm.mov(:rax, C.to_value(comptime_recv))
asm.cmp([SP, C.VALUE.size * recv_index], :rax) asm.cmp([SP, C.VALUE.size * (ctx.sp_offset - 1 - recv_index)], :rax)
asm.jne(side_exit(jit, ctx)) asm.jne(side_exit(jit, ctx))
else else
# TODO: support more classes # TODO: support more classes
@ -813,8 +810,7 @@ module RubyVM::MJIT
def jit_call_iseq_setup_normal(jit, ctx, asm, ci, cme, flags, argc, iseq) def jit_call_iseq_setup_normal(jit, ctx, asm, ci, cme, flags, argc, iseq)
# Save caller SP and PC before pushing a callee frame for backtrace and side exits # Save caller SP and PC before pushing a callee frame for backtrace and side exits
asm.comment('save SP to caller CFP') asm.comment('save SP to caller CFP')
assert_equal(ctx.sp_offset, ctx.stack_size) # TODO: support SP motion sp_index = ctx.sp_offset - 1 - argc - ((flags & C.VM_CALL_ARGS_BLOCKARG == 0) ? 0 : 1) # Pop receiver and arguments for side exits
sp_index = ctx.stack_size - 1 - argc - ((flags & C.VM_CALL_ARGS_BLOCKARG == 0) ? 0 : 1) # Pop receiver and arguments for side exits
asm.lea(:rax, [SP, C.VALUE.size * sp_index]) asm.lea(:rax, [SP, C.VALUE.size * sp_index])
asm.mov([CFP, C.rb_control_frame_t.offsetof(:sp)], :rax) asm.mov([CFP, C.rb_control_frame_t.offsetof(:sp)], :rax)
@ -837,13 +833,11 @@ module RubyVM::MJIT
local_size = iseq.body.local_table_size - iseq.body.param.size local_size = iseq.body.local_table_size - iseq.body.param.size
local_size.times do |i| local_size.times do |i|
asm.comment('set local variables') if i == 0 asm.comment('set local variables') if i == 0
assert_equal(ctx.sp_offset, ctx.stack_size) # TODO: support SP motion local_index = ctx.sp_offset + i
local_index = ctx.stack_size + i
asm.mov([SP, C.VALUE.size * local_index], Qnil) asm.mov([SP, C.VALUE.size * local_index], Qnil)
end end
assert_equal(ctx.sp_offset, ctx.stack_size) # TODO: support SP motion sp_offset = ctx.sp_offset + local_size + 3
sp_offset = ctx.stack_size + local_size + 3
asm.add(SP, C.VALUE.size * sp_offset) asm.add(SP, C.VALUE.size * sp_offset)
asm.comment('set cme') asm.comment('set cme')

View File

@ -23,6 +23,7 @@ module RubyVM::MJIT
def peek_at_stack(depth_from_top) def peek_at_stack(depth_from_top)
raise 'not at current insn' unless at_current_insn? raise 'not at current insn' unless at_current_insn?
offset = -(1 + depth_from_top) offset = -(1 + depth_from_top)
# rb_mjit_branch_stub_hit updates SP, so you don't need to worry about sp_offset
value = (cfp.sp + offset).* value = (cfp.sp + offset).*
C.to_ruby(value) C.to_ruby(value)
end end