mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Ported neg, and, or instructions
This commit is contained in:
parent
3739588811
commit
090255456a
4 changed files with 181 additions and 40 deletions
149
ujit_asm.c
149
ujit_asm.c
|
@ -746,6 +746,22 @@ void cb_write_jcc(codeblock_t* cb, const char* mnem, uint8_t op0, uint8_t op1, s
|
|||
cb_write_int(cb, 0, 32);
|
||||
}
|
||||
|
||||
// Encode a conditional move instruction
|
||||
/*
|
||||
void writeCmov(CodeBlock cb, const char mnem, ubyte opcode1, X86Reg dst, X86Opnd src)
|
||||
{
|
||||
//cb.writeASM(mnem, dst, src);
|
||||
|
||||
assert (src.isReg || src.isMem);
|
||||
assert (dst.size >= 16, "invalid dst reg size in cmov");
|
||||
|
||||
auto szPref = dst.size is 16;
|
||||
auto rexW = dst.size is 64;
|
||||
|
||||
cb.writeRMInstr!('r', 0xFF, 0x0F, opcode1)(szPref, rexW, X86Opnd(dst), src);
|
||||
}
|
||||
*/
|
||||
|
||||
// add - Integer addition
|
||||
void add(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1)
|
||||
{
|
||||
|
@ -765,6 +781,25 @@ void add(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1)
|
|||
);
|
||||
}
|
||||
|
||||
/// and - Bitwise AND
|
||||
void and(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1)
|
||||
{
|
||||
cb_write_rm_multi(
|
||||
cb,
|
||||
"and",
|
||||
0x20, // opMemReg8
|
||||
0x21, // opMemRegPref
|
||||
0x22, // opRegMem8
|
||||
0x23, // opRegMemPref
|
||||
0x80, // opMemImm8
|
||||
0x83, // opMemImmSml
|
||||
0x81, // opMemImmLrg
|
||||
0x04, // opExtImm
|
||||
opnd0,
|
||||
opnd1
|
||||
);
|
||||
}
|
||||
|
||||
/// call - Call to label with 32-bit offset
|
||||
void call_label(codeblock_t* cb, size_t label_idx)
|
||||
{
|
||||
|
@ -787,6 +822,40 @@ void call(codeblock_t* cb, x86opnd_t opnd)
|
|||
cb_write_rm(cb, false, false, NO_OPND, opnd, 2, 1, 0xFF);
|
||||
}
|
||||
|
||||
/*
|
||||
/// cmovcc - Conditional move
|
||||
alias cmova = writeCmov!("cmova", 0x47);
|
||||
alias cmovae = writeCmov!("cmovae", 0x43);
|
||||
alias cmovb = writeCmov!("cmovb", 0x42);
|
||||
alias cmovbe = writeCmov!("cmovbe", 0x46);
|
||||
alias cmovc = writeCmov!("cmovc", 0x42);
|
||||
alias cmove = writeCmov!("cmove", 0x44);
|
||||
alias cmovg = writeCmov!("cmovg", 0x4F);
|
||||
alias cmovge = writeCmov!("cmovge", 0x4D);
|
||||
alias cmovl = writeCmov!("cmovl", 0x4C);
|
||||
alias cmovle = writeCmov!("cmovle", 0x4E);
|
||||
alias cmovna = writeCmov!("cmovna", 0x46);
|
||||
alias cmovnae = writeCmov!("cmovnae", 0x42);
|
||||
alias cmovnb = writeCmov!("cmovnb", 0x43);
|
||||
alias cmovnbe = writeCmov!("cmovnbe", 0x47);
|
||||
alias cmovnc = writeCmov!("cmovnc", 0x43);
|
||||
alias cmovne = writeCmov!("cmovne", 0x45);
|
||||
alias cmovnge = writeCmov!("cmovng", 0x4E);
|
||||
alias cmovnge = writeCmov!("cmovnge", 0x4C);
|
||||
alias cmovnl = writeCmov!("cmovnl", 0x4D);
|
||||
alias cmovnle = writeCmov!("cmovnle", 0x4F);
|
||||
alias cmovno = writeCmov!("cmovno", 0x41);
|
||||
alias cmovnp = writeCmov!("cmovnp", 0x4B);
|
||||
alias cmovns = writeCmov!("cmovns", 0x49);
|
||||
alias cmovnz = writeCmov!("cmovnz", 0x45);
|
||||
alias cmovo = writeCmov!("cmovno", 0x40);
|
||||
alias cmovp = writeCmov!("cmovp", 0x4A);
|
||||
alias cmovpe = writeCmov!("cmovpe", 0x4A);
|
||||
alias cmovpo = writeCmov!("cmovpo", 0x4B);
|
||||
alias cmovs = writeCmov!("cmovs", 0x48);
|
||||
alias cmovz = writeCmov!("cmovz", 0x44);
|
||||
*/
|
||||
|
||||
/// cmp - Compare and set flags
|
||||
void cmp(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1)
|
||||
{
|
||||
|
@ -1094,6 +1163,19 @@ void mov(codeblock_t* cb, x86opnd_t dst, x86opnd_t src)
|
|||
}
|
||||
}
|
||||
|
||||
// neg - Integer negation (multiplication by -1)
|
||||
void neg(codeblock_t* cb, x86opnd_t opnd)
|
||||
{
|
||||
write_rm_unary(
|
||||
cb,
|
||||
"neg",
|
||||
0xF6, // opMemReg8
|
||||
0xF7, // opMemRegPref
|
||||
0x03, // opExt
|
||||
opnd
|
||||
);
|
||||
}
|
||||
|
||||
// nop - Noop, one or multiple bytes long
|
||||
void nop(codeblock_t* cb, size_t length)
|
||||
{
|
||||
|
@ -1174,32 +1256,23 @@ void not(codeblock_t* cb, x86opnd_t opnd)
|
|||
);
|
||||
}
|
||||
|
||||
/*
|
||||
/// or - Bitwise OR
|
||||
alias or = writeRMMulti!(
|
||||
"or",
|
||||
0x08, // opMemReg8
|
||||
0x09, // opMemRegPref
|
||||
0x0A, // opRegMem8
|
||||
0x0B, // opRegMemPref
|
||||
0x80, // opMemImm8
|
||||
0x83, // opMemImmSml
|
||||
0x81, // opMemImmLrg
|
||||
0x01 // opExtImm
|
||||
);
|
||||
*/
|
||||
|
||||
/// push - Push a register on the stack
|
||||
void push(codeblock_t* cb, x86opnd_t reg)
|
||||
void or(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1)
|
||||
{
|
||||
assert (reg.num_bits == 64);
|
||||
|
||||
//cb.writeASM("push", reg);
|
||||
|
||||
if (rex_needed(reg))
|
||||
cb_write_rex(cb, false, 0, 0, reg.reg.reg_no);
|
||||
|
||||
cb_write_opcode(cb, 0x50, reg);
|
||||
cb_write_rm_multi(
|
||||
cb,
|
||||
"or",
|
||||
0x08, // opMemReg8
|
||||
0x09, // opMemRegPref
|
||||
0x0A, // opRegMem8
|
||||
0x0B, // opRegMemPref
|
||||
0x80, // opMemImm8
|
||||
0x83, // opMemImmSml
|
||||
0x81, // opMemImmLrg
|
||||
0x01, // opExtImm
|
||||
opnd0,
|
||||
opnd1
|
||||
);
|
||||
}
|
||||
|
||||
/// pop - Pop a register off the stack
|
||||
|
@ -1215,6 +1288,19 @@ void pop(codeblock_t* cb, x86opnd_t reg)
|
|||
cb_write_opcode(cb, 0x58, reg);
|
||||
}
|
||||
|
||||
/// push - Push a register on the stack
|
||||
void push(codeblock_t* cb, x86opnd_t reg)
|
||||
{
|
||||
assert (reg.num_bits == 64);
|
||||
|
||||
//cb.writeASM("push", reg);
|
||||
|
||||
if (rex_needed(reg))
|
||||
cb_write_rex(cb, false, 0, 0, reg.reg.reg_no);
|
||||
|
||||
cb_write_opcode(cb, 0x50, reg);
|
||||
}
|
||||
|
||||
/// ret - Return from call, popping only the return address
|
||||
void ret(codeblock_t* cb)
|
||||
{
|
||||
|
@ -1299,3 +1385,18 @@ void sub(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1)
|
|||
opnd1
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
/// xor - Exclusive bitwise OR
|
||||
alias xor = writeRMMulti!(
|
||||
"xor",
|
||||
0x30, // opMemReg8
|
||||
0x31, // opMemRegPref
|
||||
0x32, // opRegMem8
|
||||
0x33, // opRegMemPref
|
||||
0x80, // opMemImm8
|
||||
0x83, // opMemImmSml
|
||||
0x81, // opMemImmLrg
|
||||
0x06 // opExtImm
|
||||
);
|
||||
*/
|
||||
|
|
|
@ -193,6 +193,7 @@ void cb_link_labels(codeblock_t* cb);
|
|||
|
||||
// Encode individual instructions into a code block
|
||||
void add(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
void and(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
void call_label(codeblock_t* cb, size_t label_idx);
|
||||
void call(codeblock_t* cb, x86opnd_t opnd);
|
||||
void cmp(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
|
@ -234,10 +235,12 @@ void jmp(codeblock_t* cb, size_t label_idx);
|
|||
void jmp_rm(codeblock_t* cb, x86opnd_t opnd);
|
||||
void lea(codeblock_t* cb, x86opnd_t dst, x86opnd_t src);
|
||||
void mov(codeblock_t* cb, x86opnd_t dst, x86opnd_t src);
|
||||
void neg(codeblock_t* cb, x86opnd_t opnd);
|
||||
void nop(codeblock_t* cb, size_t length);
|
||||
void not(codeblock_t* cb, x86opnd_t opnd);
|
||||
void push(codeblock_t* cb, x86opnd_t reg);
|
||||
void or(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
void pop(codeblock_t* cb, x86opnd_t reg);
|
||||
void push(codeblock_t* cb, x86opnd_t reg);
|
||||
void ret(codeblock_t* cb);
|
||||
void sal(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
void sar(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
|
|
|
@ -30,7 +30,7 @@ void check_bytes(codeblock_t* cb, const char* bytes)
|
|||
|
||||
if (cb_byte != byte)
|
||||
{
|
||||
fprintf(stderr, "incorrect encoding at position %ld, got %X, expected %X\n",
|
||||
fprintf(stderr, "incorrect encoding at position %ld, got %02X, expected %02X\n",
|
||||
i,
|
||||
(int)cb_byte,
|
||||
(int)byte
|
||||
|
@ -47,8 +47,6 @@ void run_tests()
|
|||
codeblock_t cb_obj;
|
||||
codeblock_t* cb = &cb_obj;
|
||||
cb_init(cb, 4096);
|
||||
cb_write_prologue(cb);
|
||||
cb_write_epilogue(cb);
|
||||
|
||||
// add
|
||||
/*
|
||||
|
@ -82,6 +80,9 @@ void run_tests()
|
|||
cb_set_pos(cb, 0); add(cb, ECX, imm_opnd(8)); check_bytes(cb, "83C108");
|
||||
cb_set_pos(cb, 0); add(cb, ECX, imm_opnd(255)); check_bytes(cb, "81C1FF000000");
|
||||
|
||||
// and
|
||||
cb_set_pos(cb, 0); and(cb, EBP, R12D); check_bytes(cb, "4421E5");
|
||||
|
||||
// call
|
||||
{
|
||||
cb_set_pos(cb, 0);
|
||||
|
@ -212,6 +213,10 @@ void run_tests()
|
|||
);
|
||||
*/
|
||||
cb_set_pos(cb, 0); mov(cb, mem_opnd(8, RSP, 0), imm_opnd(-3)); check_bytes(cb, "C60424FD");
|
||||
cb_set_pos(cb, 0); mov(cb, mem_opnd(64, RDI, 8), imm_opnd(1)); check_bytes(cb, "48C7470801000000");
|
||||
|
||||
// neg
|
||||
cb_set_pos(cb, 0); neg(cb, RAX); check_bytes(cb, "48F7D8");
|
||||
|
||||
// nop
|
||||
cb_set_pos(cb, 0); nop(cb, 1); check_bytes(cb, "90");
|
||||
|
@ -295,12 +300,7 @@ void run_tests()
|
|||
*/
|
||||
|
||||
// or
|
||||
/*
|
||||
test(
|
||||
delegate void (CodeBlock cb) { cb.or(X86Opnd(EDX), X86Opnd(ESI)); },
|
||||
"09F2"
|
||||
);
|
||||
*/
|
||||
cb_set_pos(cb, 0); or(cb, EDX, ESI); check_bytes(cb, "09F2");
|
||||
|
||||
// pop
|
||||
cb_set_pos(cb, 0); pop(cb, RAX); check_bytes(cb, "58");
|
||||
|
@ -346,6 +346,14 @@ void run_tests()
|
|||
cb_set_pos(cb, 0); sub(cb, EAX, imm_opnd(1)); check_bytes(cb, "83E801");
|
||||
cb_set_pos(cb, 0); sub(cb, RAX, imm_opnd(2)); check_bytes(cb, "4883E802");
|
||||
|
||||
/*
|
||||
// xor
|
||||
test(
|
||||
delegate void (CodeBlock cb) { cb.xor(X86Opnd(EAX), X86Opnd(EAX)); },
|
||||
"31C0"
|
||||
);
|
||||
*/
|
||||
|
||||
printf("Assembler tests done\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,11 @@ ujit_compile_insn(rb_iseq_t *iseq, size_t insn_idx)
|
|||
ujit_init();
|
||||
}
|
||||
|
||||
if (cb->write_pos + 1024 >= cb->mem_size)
|
||||
{
|
||||
rb_bug("out of executable memory");
|
||||
}
|
||||
|
||||
int insn = (int)iseq->body->iseq_encoded[insn_idx];
|
||||
int len = insn_len(insn);
|
||||
//const char* name = insn_name(insn);
|
||||
|
@ -74,6 +79,9 @@ ujit_compile_insn(rb_iseq_t *iseq, size_t insn_idx)
|
|||
uint8_t* code_ptr = &cb->mem_block[cb->write_pos];
|
||||
//printf("write pos: %ld\n", cb->write_pos);
|
||||
|
||||
// Write the pre call bytes
|
||||
ujit_instr_entry(cb);
|
||||
|
||||
// TODO: encode individual instructions, eg
|
||||
// nop, putnil, putobject, putself, pop, dup, getlocal, setlocal, nilp
|
||||
|
||||
|
@ -81,9 +89,6 @@ ujit_compile_insn(rb_iseq_t *iseq, size_t insn_idx)
|
|||
// into separate functions
|
||||
if (insn == BIN(nop))
|
||||
{
|
||||
// Write the pre call bytes
|
||||
ujit_instr_entry(cb);
|
||||
|
||||
//add(cb, RSI, imm_opnd(8)); // increment PC
|
||||
//mov(cb, mem_opnd(64, RDI, 0), RSI); // write new PC to EC object, not necessary for nop bytecode?
|
||||
//mov(cb, RAX, RSI); // return new PC
|
||||
|
@ -101,10 +106,34 @@ ujit_compile_insn(rb_iseq_t *iseq, size_t insn_idx)
|
|||
|
||||
if (insn == BIN(pop))
|
||||
{
|
||||
// Write the pre call bytes
|
||||
ujit_instr_entry(cb);
|
||||
// Decrement SP
|
||||
sub(cb, mem_opnd(64, RDI, 8), imm_opnd(8));
|
||||
|
||||
sub(cb, mem_opnd(64, RDI, 8), imm_opnd(8)); // decrement SP
|
||||
// Directly return the next PC, which is a constant
|
||||
mov(cb, RAX, const_ptr_opnd(next_pc));
|
||||
|
||||
// Write the post call bytes
|
||||
ujit_instr_exit(cb);
|
||||
|
||||
addr2insn_bookkeeping(code_ptr, insn);
|
||||
|
||||
return code_ptr;
|
||||
}
|
||||
|
||||
if (insn == BIN(putobject_INT2FIX_0_) || insn == BIN(putobject_INT2FIX_1_))
|
||||
{
|
||||
// Load current SP into RAX
|
||||
mov(cb, RAX, mem_opnd(64, RDI, 8));
|
||||
|
||||
// Write constant at SP
|
||||
int cst = (insn == BIN(putobject_INT2FIX_0_))? 0:1;
|
||||
mov(cb, mem_opnd(64, RAX, 0), imm_opnd(INT2FIX(cst)));
|
||||
|
||||
// Load incremented SP into RCX
|
||||
lea(cb, RCX, mem_opnd(64, RAX, 8));
|
||||
|
||||
// Write back incremented SP
|
||||
mov(cb, mem_opnd(64, RDI, 8), RCX);
|
||||
|
||||
// Directly return the next PC, which is a constant
|
||||
mov(cb, RAX, const_ptr_opnd(next_pc));
|
||||
|
|
Loading…
Reference in a new issue