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
|
||||
insn(opcode: 0xe8, imm: rel32(dst_addr))
|
||||
# CALL r/m64 (Mod 11: reg)
|
||||
in Symbol => dst_reg
|
||||
in Symbol => dst_reg if r64?(dst_reg)
|
||||
# FF /2
|
||||
# M: Operand 1: ModRM:r/m (r)
|
||||
insn(
|
||||
@ -172,7 +172,7 @@ module RubyVM::RJIT
|
||||
def cmove(dst, src)
|
||||
case [dst, src]
|
||||
# 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
|
||||
# RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
|
||||
insn(
|
||||
@ -188,7 +188,7 @@ module RubyVM::RJIT
|
||||
def cmovg(dst, src)
|
||||
case [dst, src]
|
||||
# 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
|
||||
# RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
|
||||
insn(
|
||||
@ -204,7 +204,7 @@ module RubyVM::RJIT
|
||||
def cmovge(dst, src)
|
||||
case [dst, src]
|
||||
# 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
|
||||
# RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
|
||||
insn(
|
||||
@ -220,7 +220,7 @@ module RubyVM::RJIT
|
||||
def cmovl(dst, src)
|
||||
case [dst, src]
|
||||
# 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
|
||||
# RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
|
||||
insn(
|
||||
@ -236,7 +236,7 @@ module RubyVM::RJIT
|
||||
def cmovle(dst, src)
|
||||
case [dst, src]
|
||||
# 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
|
||||
# RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
|
||||
insn(
|
||||
@ -431,11 +431,11 @@ module RubyVM::RJIT
|
||||
# E9 cd
|
||||
insn(opcode: 0xe9, imm: rel32(dst_addr))
|
||||
# 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
|
||||
insn(opcode: 0xff, mod_rm: ModRM[mod: Mod01, reg: 4, rm: dst_reg], disp: dst_disp)
|
||||
# JMP r/m64 (Mod 11: reg)
|
||||
in Symbol => dst_reg
|
||||
in Symbol => dst_reg if r64?(dst_reg)
|
||||
# FF /4
|
||||
insn(opcode: 0xff, mod_rm: ModRM[mod: Mod11, reg: 4, rm: dst_reg])
|
||||
else
|
||||
|
@ -19,24 +19,270 @@ module RubyVM::RJIT
|
||||
|
||||
def test_add
|
||||
asm = Assembler.new
|
||||
asm.add(:rax, 255)
|
||||
assert_compile(asm, '0x0: add rax, 0xff')
|
||||
asm.add([:rcx], 1) # ADD r/m64, imm8 (Mod 00: [reg])
|
||||
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
|
||||
|
||||
def test_jmp
|
||||
asm = Assembler.new
|
||||
label = asm.new_label('label')
|
||||
asm.jmp(label)
|
||||
asm.jmp(label) # JZ rel8
|
||||
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)
|
||||
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
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def rel32(offset)
|
||||
@cb.write_addr + 0xff
|
||||
end
|
||||
|
||||
def assert_compile(asm, expected)
|
||||
actual = compile(asm)
|
||||
assert_equal expected, actual, "---\n#{actual}---"
|
||||
@ -54,8 +300,13 @@ module RubyVM::RJIT
|
||||
|
||||
disasm.gsub!(/^ /, '')
|
||||
disasm.sub!(/\n\z/, '')
|
||||
if disasm.lines.size == 1
|
||||
disasm.rstrip!
|
||||
disasm.gsub!(/0x(\h{12})/) do
|
||||
offset = $1.to_i(16) - start_addr
|
||||
if offset.negative?
|
||||
"-0x#{offset.to_s(16)}"
|
||||
else
|
||||
"0x#{offset.to_s(16)}"
|
||||
end
|
||||
end
|
||||
(start_addr...end_addr).each do |addr|
|
||||
disasm.gsub!("0x#{addr.to_s(16)}", "0x#{(addr - start_addr).to_s(16)}")
|
||||
|
Loading…
x
Reference in New Issue
Block a user