summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ujit_asm.c143
-rw-r--r--ujit_asm.h5
-rw-r--r--ujit_asm_tests.c26
-rw-r--r--ujit_compile.c41
4 files changed, 178 insertions, 37 deletions
diff --git a/ujit_asm.c b/ujit_asm.c
index 67e739f8ad..ce0e9fb2fe 100644
--- a/ujit_asm.c
+++ b/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,45 +1256,49 @@ 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
-);
-*/
+void or(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1)
+{
+ cb_write_rm_multi(
+ cb,
+ "or",
+ 0x08, // opMemReg8
+ 0x09, // opMemRegPref
+ 0x0A, // opRegMem8
+ 0x0B, // opRegMemPref
+ 0x80, // opMemImm8
+ 0x83, // opMemImmSml
+ 0x81, // opMemImmLrg
+ 0x01, // opExtImm
+ opnd0,
+ opnd1
+ );
+}
-/// push - Push a register on the stack
-void push(codeblock_t* cb, x86opnd_t reg)
+/// pop - Pop a register off the stack
+void pop(codeblock_t* cb, x86opnd_t reg)
{
assert (reg.num_bits == 64);
- //cb.writeASM("push", reg);
+ //cb.writeASM("pop", reg);
if (rex_needed(reg))
cb_write_rex(cb, false, 0, 0, reg.reg.reg_no);
- cb_write_opcode(cb, 0x50, reg);
+ cb_write_opcode(cb, 0x58, reg);
}
-/// pop - Pop a register off the stack
-void pop(codeblock_t* cb, x86opnd_t reg)
+/// push - Push a register on the stack
+void push(codeblock_t* cb, x86opnd_t reg)
{
assert (reg.num_bits == 64);
- //cb.writeASM("pop", reg);
+ //cb.writeASM("push", reg);
if (rex_needed(reg))
cb_write_rex(cb, false, 0, 0, reg.reg.reg_no);
- cb_write_opcode(cb, 0x58, reg);
+ cb_write_opcode(cb, 0x50, reg);
}
/// ret - Return from call, popping only the return address
@@ -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
+);
+*/
diff --git a/ujit_asm.h b/ujit_asm.h
index af8f0d7fc7..569c310381 100644
--- a/ujit_asm.h
+++ b/ujit_asm.h
@@ -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);
diff --git a/ujit_asm_tests.c b/ujit_asm_tests.c
index 4ada3a9ecd..e163404d05 100644
--- a/ujit_asm_tests.c
+++ b/ujit_asm_tests.c
@@ -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");
}
diff --git a/ujit_compile.c b/ujit_compile.c
index 19b2b35c12..88eb2d657e 100644
--- a/ujit_compile.c
+++ b/ujit_compile.c
@@ -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));
+
+ // 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));
- sub(cb, mem_opnd(64, RDI, 8), imm_opnd(8)); // decrement SP
+ // 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));