RJIT: Write initial tests for Assembler
This commit is contained in:
parent
83f6eee76c
commit
93e34fe42e
@ -157,7 +157,7 @@ module RubyVM::RJIT
|
|||||||
# D: Operand 1: Offset
|
# D: Operand 1: Offset
|
||||||
insn(opcode: 0xe8, imm: rel32(dst_addr))
|
insn(opcode: 0xe8, imm: rel32(dst_addr))
|
||||||
# CALL r/m64 (Mod 11: reg)
|
# CALL r/m64 (Mod 11: reg)
|
||||||
in Symbol => dst_reg
|
in Symbol => dst_reg if r64?(dst_reg)
|
||||||
# FF /2
|
# FF /2
|
||||||
# M: Operand 1: ModRM:r/m (r)
|
# M: Operand 1: ModRM:r/m (r)
|
||||||
insn(
|
insn(
|
||||||
@ -172,7 +172,7 @@ module RubyVM::RJIT
|
|||||||
def cmove(dst, src)
|
def cmove(dst, src)
|
||||||
case [dst, src]
|
case [dst, src]
|
||||||
# CMOVE r64, r/m64 (Mod 11: reg)
|
# CMOVE r64, r/m64 (Mod 11: reg)
|
||||||
in [Symbol => dst_reg, Symbol => src_reg]
|
in [Symbol => dst_reg, Symbol => src_reg] if r64?(dst_reg) && r64?(src_reg)
|
||||||
# REX.W + 0F 44 /r
|
# REX.W + 0F 44 /r
|
||||||
# RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
|
# RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
|
||||||
insn(
|
insn(
|
||||||
@ -188,7 +188,7 @@ module RubyVM::RJIT
|
|||||||
def cmovg(dst, src)
|
def cmovg(dst, src)
|
||||||
case [dst, src]
|
case [dst, src]
|
||||||
# CMOVG r64, r/m64 (Mod 11: reg)
|
# CMOVG r64, r/m64 (Mod 11: reg)
|
||||||
in [Symbol => dst_reg, Symbol => src_reg]
|
in [Symbol => dst_reg, Symbol => src_reg] if r64?(dst_reg) && r64?(src_reg)
|
||||||
# REX.W + 0F 4F /r
|
# REX.W + 0F 4F /r
|
||||||
# RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
|
# RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
|
||||||
insn(
|
insn(
|
||||||
@ -204,7 +204,7 @@ module RubyVM::RJIT
|
|||||||
def cmovge(dst, src)
|
def cmovge(dst, src)
|
||||||
case [dst, src]
|
case [dst, src]
|
||||||
# CMOVGE r64, r/m64 (Mod 11: reg)
|
# CMOVGE r64, r/m64 (Mod 11: reg)
|
||||||
in [Symbol => dst_reg, Symbol => src_reg]
|
in [Symbol => dst_reg, Symbol => src_reg] if r64?(dst_reg) && r64?(src_reg)
|
||||||
# REX.W + 0F 4D /r
|
# REX.W + 0F 4D /r
|
||||||
# RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
|
# RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
|
||||||
insn(
|
insn(
|
||||||
@ -220,7 +220,7 @@ module RubyVM::RJIT
|
|||||||
def cmovl(dst, src)
|
def cmovl(dst, src)
|
||||||
case [dst, src]
|
case [dst, src]
|
||||||
# CMOVL r64, r/m64 (Mod 11: reg)
|
# CMOVL r64, r/m64 (Mod 11: reg)
|
||||||
in [Symbol => dst_reg, Symbol => src_reg]
|
in [Symbol => dst_reg, Symbol => src_reg] if r64?(dst_reg) && r64?(src_reg)
|
||||||
# REX.W + 0F 4C /r
|
# REX.W + 0F 4C /r
|
||||||
# RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
|
# RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
|
||||||
insn(
|
insn(
|
||||||
@ -236,7 +236,7 @@ module RubyVM::RJIT
|
|||||||
def cmovle(dst, src)
|
def cmovle(dst, src)
|
||||||
case [dst, src]
|
case [dst, src]
|
||||||
# CMOVLE r64, r/m64 (Mod 11: reg)
|
# CMOVLE r64, r/m64 (Mod 11: reg)
|
||||||
in [Symbol => dst_reg, Symbol => src_reg]
|
in [Symbol => dst_reg, Symbol => src_reg] if r64?(dst_reg) && r64?(src_reg)
|
||||||
# REX.W + 0F 4E /r
|
# REX.W + 0F 4E /r
|
||||||
# RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
|
# RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
|
||||||
insn(
|
insn(
|
||||||
@ -431,11 +431,11 @@ module RubyVM::RJIT
|
|||||||
# E9 cd
|
# E9 cd
|
||||||
insn(opcode: 0xe9, imm: rel32(dst_addr))
|
insn(opcode: 0xe9, imm: rel32(dst_addr))
|
||||||
# JMP r/m64 (Mod 01: [reg]+disp8)
|
# JMP r/m64 (Mod 01: [reg]+disp8)
|
||||||
in Array[Symbol => dst_reg, Integer => dst_disp] if imm8?(dst_disp)
|
in Array[Symbol => dst_reg, Integer => dst_disp] if r64?(dst_reg) && imm8?(dst_disp)
|
||||||
# FF /4
|
# FF /4
|
||||||
insn(opcode: 0xff, mod_rm: ModRM[mod: Mod01, reg: 4, rm: dst_reg], disp: dst_disp)
|
insn(opcode: 0xff, mod_rm: ModRM[mod: Mod01, reg: 4, rm: dst_reg], disp: dst_disp)
|
||||||
# JMP r/m64 (Mod 11: reg)
|
# JMP r/m64 (Mod 11: reg)
|
||||||
in Symbol => dst_reg
|
in Symbol => dst_reg if r64?(dst_reg)
|
||||||
# FF /4
|
# FF /4
|
||||||
insn(opcode: 0xff, mod_rm: ModRM[mod: Mod11, reg: 4, rm: dst_reg])
|
insn(opcode: 0xff, mod_rm: ModRM[mod: Mod11, reg: 4, rm: dst_reg])
|
||||||
else
|
else
|
||||||
|
@ -19,24 +19,270 @@ module RubyVM::RJIT
|
|||||||
|
|
||||||
def test_add
|
def test_add
|
||||||
asm = Assembler.new
|
asm = Assembler.new
|
||||||
asm.add(:rax, 255)
|
asm.add([:rcx], 1) # ADD r/m64, imm8 (Mod 00: [reg])
|
||||||
assert_compile(asm, '0x0: add rax, 0xff')
|
asm.add(:rax, 0x7f) # ADD r/m64, imm8 (Mod 11: reg)
|
||||||
|
asm.add(:rbx, 0x7fffffff) # ADD r/m64 imm32 (Mod 11: reg)
|
||||||
|
asm.add(:rsi, :rdi) # ADD r/m64, r64 (Mod 11: reg)
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: add qword ptr [rcx], 1
|
||||||
|
0x4: add rax, 0x7f
|
||||||
|
0x8: add rbx, 0x7fffffff
|
||||||
|
0xf: add rsi, rdi
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_and
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.and(:rax, 0) # AND r/m64, imm8 (Mod 11: reg)
|
||||||
|
asm.and(:rbx, 0x7fffffff) # AND r/m64, imm32 (Mod 11: reg)
|
||||||
|
asm.and(:rcx, [:rdi, 8]) # AND r64, r/m64 (Mod 01: [reg]+disp8)
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: and rax, 0
|
||||||
|
0x4: and rbx, 0x7fffffff
|
||||||
|
0xb: and rcx, qword ptr [rdi + 8]
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_call
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.call(rel32(0xff)) # CALL rel32
|
||||||
|
asm.call(:rax) # CALL r/m64 (Mod 11: reg)
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: call 0xff
|
||||||
|
0x5: call rax
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cmove
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.cmove(:rax, :rcx) # CMOVE r64, r/m64 (Mod 11: reg)
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: cmove rax, rcx
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cmovg
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.cmovg(:rbx, :rdi) # CMOVG r64, r/m64 (Mod 11: reg)
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: cmovg rbx, rdi
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cmovge
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.cmovge(:rsp, :rbp) # CMOVGE r64, r/m64 (Mod 11: reg)
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: cmovge rsp, rbp
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cmovl
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.cmovl(:rdx, :rsp) # CMOVL r64, r/m64 (Mod 11: reg)
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: cmovl rdx, rsp
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cmovle
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.cmovle(:rax, :rax) # CMOVLE r64, r/m64 (Mod 11: reg)
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: cmovle rax, rax
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cmovnz
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.cmovnz(:rax, :rbx) # CMOVNZ r64, r/m64 (Mod 11: reg)
|
||||||
|
assert_compile(asm, <<~EOS) # cmovne == cmovnz
|
||||||
|
0x0: cmovne rax, rbx
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cmovz
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.cmovz(:rax, :rbx) # CMOVZ r64, r/m64 (Mod 11: reg)
|
||||||
|
assert_compile(asm, <<~EOS) # cmove == cmovz
|
||||||
|
0x0: cmove rax, rbx
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cmp
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.cmp(:rax, 0) # CMP r/m64, imm8 (Mod 11: reg)
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: cmp rax, 0
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_jbe
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.jbe(rel32(0xff)) # JBE rel32
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: jbe 0xff
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_je
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.je(rel32(0xff)) # JE rel32
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: je 0xff
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_jl
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.jl(rel32(0xff)) # JL rel32
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: jl 0xff
|
||||||
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_jmp
|
def test_jmp
|
||||||
asm = Assembler.new
|
asm = Assembler.new
|
||||||
label = asm.new_label('label')
|
label = asm.new_label('label')
|
||||||
asm.jmp(label)
|
asm.jmp(label) # JZ rel8
|
||||||
asm.write_label(label)
|
asm.write_label(label)
|
||||||
asm.jmp(label)
|
asm.jmp(rel32(0xff)) # JMP rel32
|
||||||
|
asm.jmp([:rax, 8]) # JMP r/m64 (Mod 01: [reg]+disp8)
|
||||||
|
asm.jmp(:rax) # JMP r/m64 (Mod 11: reg)
|
||||||
assert_compile(asm, <<~EOS)
|
assert_compile(asm, <<~EOS)
|
||||||
0x0: jmp 0x2
|
0x0: jmp 0x2
|
||||||
0x2: jmp 0x2
|
0x2: jmp 0xff
|
||||||
|
0x7: jmp qword ptr [rax + 8]
|
||||||
|
0xa: jmp rax
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_jne
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.jne(rel32(0xff)) # JNE rel32
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: jne 0xff
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_jnz
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.jnz(rel32(0xff)) # JNZ rel32
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: jne 0xff
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_jo
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.jo(rel32(0xff)) # JO rel32
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: jo 0xff
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_jz
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.jz(rel32(0xff)) # JZ rel32
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: je 0xff
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_lea
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.lea(:rax, [:rax, 8]) # LEA r64,m (Mod 01: [reg]+disp8)
|
||||||
|
asm.lea(:rax, [:rax, 0xffff]) # LEA r64,m (Mod 10: [reg]+disp32)
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: lea rax, [rax + 8]
|
||||||
|
0x4: lea rax, [rax + 0xffff]
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_mov
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.mov(:rax, :rbx) # MOV r64, r/m64 (Mod 00: [reg])
|
||||||
|
asm.mov(:rax, [:rbx, 8]) # MOV r64, r/m64 (Mod 01: [reg]+disp8)
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: mov rax, rbx
|
||||||
|
0x3: mov rax, qword ptr [rbx + 8]
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_or
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.or(:rax, 0) # OR r/m64, imm8 (Mod 11: reg)
|
||||||
|
asm.or(:rax, 0xffff) # OR r/m64, imm32 (Mod 11: reg)
|
||||||
|
asm.or(:rax, [:rbx, 8]) # OR r64, r/m64 (Mod 01: [reg]+disp8)
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: or rax, 0
|
||||||
|
0x4: or rax, 0xffff
|
||||||
|
0xb: or rax, qword ptr [rbx + 8]
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_push
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.push(:rax) # PUSH r64
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: push rax
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_pop
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.pop(:rax) # POP r64
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: pop rax
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_ret
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.ret # RET
|
||||||
|
assert_compile(asm, "0x0: ret \n")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_sar
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.sar(:rax, 0) # SAR r/m64, imm8 (Mod 11: reg)
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: sar rax, 0
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_sub
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.sub(:rax, 0) # SUB r/m64, imm8 (Mod 11: reg)
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: sub rax, 0
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_test
|
||||||
|
asm = Assembler.new
|
||||||
|
asm.test(BytePtr[:rax, 8], 16) # TEST r/m8*, imm8 (Mod 01: [reg]+disp8)
|
||||||
|
asm.test([:rax, 8], 8) # TEST r/m64, imm32 (Mod 01: [reg]+disp8)
|
||||||
|
asm.test([:rax, 0xffff], 0xffff) # TEST r/m64, imm32 (Mod 10: [reg]+disp32)
|
||||||
|
asm.test(:rax, 0xffff) # TEST r/m64, imm32 (Mod 11: reg)
|
||||||
|
asm.test(:eax, :ebx) # TEST r/m32, r32 (Mod 11: reg)
|
||||||
|
asm.test(:rax, :rbx) # TEST r/m64, r64 (Mod 11: reg)
|
||||||
|
assert_compile(asm, <<~EOS)
|
||||||
|
0x0: test byte ptr [rax + 8], 0x10
|
||||||
|
0x4: test qword ptr [rax + 8], 8
|
||||||
|
0xc: test qword ptr [rax + 0xffff], 0xffff
|
||||||
|
0x17: test rax, 0xffff
|
||||||
|
0x1e: test eax, ebx
|
||||||
|
0x20: test rax, rbx
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def rel32(offset)
|
||||||
|
@cb.write_addr + 0xff
|
||||||
|
end
|
||||||
|
|
||||||
def assert_compile(asm, expected)
|
def assert_compile(asm, expected)
|
||||||
actual = compile(asm)
|
actual = compile(asm)
|
||||||
assert_equal expected, actual, "---\n#{actual}---"
|
assert_equal expected, actual, "---\n#{actual}---"
|
||||||
@ -54,8 +300,13 @@ module RubyVM::RJIT
|
|||||||
|
|
||||||
disasm.gsub!(/^ /, '')
|
disasm.gsub!(/^ /, '')
|
||||||
disasm.sub!(/\n\z/, '')
|
disasm.sub!(/\n\z/, '')
|
||||||
if disasm.lines.size == 1
|
disasm.gsub!(/0x(\h{12})/) do
|
||||||
disasm.rstrip!
|
offset = $1.to_i(16) - start_addr
|
||||||
|
if offset.negative?
|
||||||
|
"-0x#{offset.to_s(16)}"
|
||||||
|
else
|
||||||
|
"0x#{offset.to_s(16)}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
(start_addr...end_addr).each do |addr|
|
(start_addr...end_addr).each do |addr|
|
||||||
disasm.gsub!("0x#{addr.to_s(16)}", "0x#{(addr - start_addr).to_s(16)}")
|
disasm.gsub!("0x#{addr.to_s(16)}", "0x#{(addr - start_addr).to_s(16)}")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user