Compile putnil properly

This commit is contained in:
Takashi Kokubun 2022-12-20 21:54:54 -08:00
parent 8deb0438c4
commit 145c937f3f
3 changed files with 65 additions and 37 deletions

View file

@ -1,14 +1,21 @@
module RubyVM::MJIT module RubyVM::MJIT
# ec: rdi
# cfp: rsi
# sp: rbx
# scratch regs: rax
class InsnCompiler class InsnCompiler
def putnil(_asm) # Ruby constants
# TODO Qnil = Fiddle::Qnil
def putnil(asm)
asm.mov([:rbx], Qnil)
KeepCompiling KeepCompiling
end end
def leave(asm) def leave(asm)
# pop the current frame (ec->cfp++) # pop the current frame (ec->cfp++)
asm.add(:rsi, C.rb_control_frame_t.size) asm.add(:rsi, C.rb_control_frame_t.size) # rsi = cfp + 1
asm.mov([:rdi, C.rb_execution_context_t.offsetof(:cfp)], :rsi) asm.mov([:rdi, C.rb_execution_context_t.offsetof(:cfp)], :rsi) # ec->cfp = rsi
# return a value # return a value
asm.mov(:rax, 1001) asm.mov(:rax, 1001)

View file

@ -43,14 +43,24 @@ module RubyVM::MJIT
def mov(dst, src) def mov(dst, src)
case [dst, src] case [dst, src]
# MOV r/m64, imm32 # MOV r/m64, imm32 (Mod 00)
in [[Symbol => dst_reg], Integer => src_imm] if r_reg?(dst_reg)
# REX.W + C7 /0 id
# MI: Operand 1: ModRM:r/m (w), Operand 2: imm8/16/32/64
insn(
prefix: REX_W,
opcode: 0xc7,
mod_rm: mod_rm(mod: 0b00, rm: reg_code(dst_reg)), # Mod 00: [reg]
imm: imm32(src_imm),
)
# MOV r/m64, imm32 (Mod 11)
in [Symbol => dst_reg, Integer => src_imm] if r_reg?(dst_reg) in [Symbol => dst_reg, Integer => src_imm] if r_reg?(dst_reg)
# REX.W + C7 /0 id # REX.W + C7 /0 id
# MI: Operand 1: ModRM:r/m (w), Operand 2: imm8/16/32/64 # MI: Operand 1: ModRM:r/m (w), Operand 2: imm8/16/32/64
insn( insn(
prefix: REX_W, prefix: REX_W,
opcode: 0xc7, opcode: 0xc7,
mod_rm: mod_rm(mod: 0b11, rm: reg_code(dst_reg)), mod_rm: mod_rm(mod: 0b11, rm: reg_code(dst_reg)), # Mod 11: reg
imm: imm32(src_imm), imm: imm32(src_imm),
) )
# MOV r/m64, r64 # MOV r/m64, r64
@ -60,9 +70,19 @@ module RubyVM::MJIT
insn( insn(
prefix: REX_W, prefix: REX_W,
opcode: 0x89, opcode: 0x89,
mod_rm: mod_rm(mod: 0b01, reg: reg_code(src_reg), rm: reg_code(dst_reg)), # disp8 mod_rm: mod_rm(mod: 0b01, reg: reg_code(src_reg), rm: reg_code(dst_reg)), # Mod 01: [reg]+disp8
disp: dst_offset, disp: dst_offset,
) )
# MOV r64, r/m64
in [Symbol => dst_reg, [Symbol => src_reg, Integer => src_offset]] if r_reg?(dst_reg) && r_reg?(src_reg) && src_offset <= 0xff
# REX.W + 8B /r
# RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r)
insn(
prefix: REX_W,
opcode: 0x8b,
mod_rm: mod_rm(mod: 0b01, reg: reg_code(dst_reg), rm: reg_code(src_reg)), # Mod 01: [reg]+disp8
disp: src_offset,
)
else else
raise NotImplementedError, "mov: not-implemented input: #{dst.inspect}, #{src.inspect}" raise NotImplementedError, "mov: not-implemented input: #{dst.inspect}, #{src.inspect}"
end end

View file

@ -9,9 +9,6 @@ module RubyVM::MJIT
EndBlock = :end_block EndBlock = :end_block
class Compiler class Compiler
# Ruby constants
Qundef = Fiddle::Qundef
attr_accessor :write_pos attr_accessor :write_pos
# @param mem_block [Integer] JIT buffer address # @param mem_block [Integer] JIT buffer address
@ -24,7 +21,11 @@ module RubyVM::MJIT
# @param iseq [RubyVM::MJIT::CPointer::Struct] # @param iseq [RubyVM::MJIT::CPointer::Struct]
def call(iseq) def call(iseq)
return if iseq.body.location.label == '<main>' return if iseq.body.location.label == '<main>'
iseq.body.jit_func = compile_block(iseq)
asm = X86Assembler.new
compile_prologue(asm)
compile_block(asm, iseq)
iseq.body.jit_func = compile(asm)
rescue Exception => e rescue Exception => e
$stderr.puts e.full_message # TODO: check verbose $stderr.puts e.full_message # TODO: check verbose
end end
@ -35,6 +36,32 @@ module RubyVM::MJIT
private private
# ec: rdi
# cfp: rsi
def compile_prologue(asm)
asm.mov(:rbx, [:rsi, C.rb_control_frame_t.offsetof(:sp)]) # rbx = cfp->sp
end
def compile_block(asm, iseq)
index = 0
while index < iseq.body.iseq_size
insn = decode_insn(iseq.body.iseq_encoded[index])
status = compile_insn(asm, insn)
if status == EndBlock
break
end
index += insn.len
end
end
def compile_insn(asm, insn)
case insn.name
when :putnil then @insn_compiler.putnil(asm)
when :leave then @insn_compiler.leave(asm)
else raise NotImplementedError, "insn '#{insn.name}' is not supported yet"
end
end
def compile(asm) def compile(asm)
start_addr = write_addr start_addr = write_addr
@ -49,32 +76,6 @@ module RubyVM::MJIT
start_addr start_addr
end end
# ec -> RDI, cfp -> RSI
def compile_block(iseq)
addr = write_addr
asm = X86Assembler.new
index = 0
while index < iseq.body.iseq_size
insn = decode_insn(iseq.body.iseq_encoded[index])
status = compile_insn(asm, insn)
if status == EndBlock
break
end
index += insn.len
end
compile(asm)
end
def compile_insn(asm, insn)
case insn.name
when :putnil then @insn_compiler.putnil(asm)
when :leave then @insn_compiler.leave(asm)
else raise NotImplementedError, "insn '#{insn.name}' is not supported yet"
end
end
def decode_insn(encoded) def decode_insn(encoded)
INSNS.fetch(C.rb_vm_insn_decode(encoded)) INSNS.fetch(C.rb_vm_insn_decode(encoded))
end end