1
0
Fork 0
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:
Maxime Chevalier-Boisvert 2020-09-14 16:59:39 -04:00 committed by Alan Wu
parent 3739588811
commit 090255456a
4 changed files with 181 additions and 40 deletions

View file

@ -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
);
*/

View file

@ -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);

View file

@ -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");
}

View file

@ -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));