ruby-changes:68683
From: Maxime <ko1@a...>
Date: Thu, 21 Oct 2021 08:12:20 +0900 (JST)
Subject: [ruby-changes:68683] 7d0df31d7a (master): Ported inc/dec instructions
https://git.ruby-lang.org/ruby.git/commit/?id=7d0df31d7a From 7d0df31d7ab834526a0b5450128602c04fddb2b0 Mon Sep 17 00:00:00 2001 From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...> Date: Fri, 11 Sep 2020 16:42:51 -0400 Subject: Ported inc/dec instructions --- ujit_asm.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++---- ujit_asm.h | 2 + ujit_asm_tests.c | 32 ++++++++++ ujit_compile.c | 2 +- 4 files changed, 199 insertions(+), 12 deletions(-) diff --git a/ujit_asm.c b/ujit_asm.c index b69d37e4b4..2cebc8caa6 100644 --- a/ujit_asm.c +++ b/ujit_asm.c @@ -555,6 +555,35 @@ void cb_write_rm( https://github.com/ruby/ruby/blob/trunk/ujit_asm.c#L555 } } +// Encode a mul-like single-operand RM instruction +void write_rm_unary( + codeblock_t* cb, + const char* mnem, + uint8_t opMemReg8, + uint8_t opMemRegPref, + uint8_t opExt, + x86opnd_t opnd) +{ + // Write a disassembly string + //cb.writeASM(mnem, opnd); + + // Check the size of opnd0 + size_t opndSize; + if (opnd.type == OPND_REG || opnd.type == OPND_MEM) + opndSize = opnd.num_bits; + else + assert (false && "invalid operand"); + + assert (opndSize == 8 || opndSize == 16 || opndSize == 32 || opndSize == 64); + bool szPref = opndSize == 16; + bool rexW = opndSize == 64; + + if (opndSize == 8) + cb_write_rm(cb, false, false, NO_OPND, opnd, opExt, 1, opMemReg8); + else + cb_write_rm(cb, szPref, rexW, NO_OPND, opnd, opExt, 1, opMemRegPref); +} + // Encode an add-like RM instruction with multiple possible encodings void cb_write_rm_multi( codeblock_t* cb, @@ -704,6 +733,23 @@ void cb_write_shift( https://github.com/ruby/ruby/blob/trunk/ujit_asm.c#L733 } } +// Encode a relative jump to a label (direct or conditional) +// Note: this always encodes a 32-bit offset +void cb_write_jcc(codeblock_t* cb, const char* mnem, uint8_t op0, uint8_t op1, size_t label_idx) +{ + //cb.writeASM(mnem, label); + + // Write the opcode + cb_write_byte(cb, op0); + cb_write_byte(cb, op1); + + // Add a reference to the label + cb_label_ref(cb, label_idx); + + // Relative 32-bit offset to be patched + cb_write_int(cb, 0, 32); +} + // add - Integer addition void add(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1) { @@ -745,21 +791,128 @@ void call(codeblock_t* cb, x86opnd_t opnd) https://github.com/ruby/ruby/blob/trunk/ujit_asm.c#L791 cb_write_rm(cb, false, false, NO_OPND, opnd, 2, 1, 0xFF); } -// Encode a relative jump to a label (direct or conditional) -// Note: this always encodes a 32-bit offset -void cb_write_jcc(codeblock_t* cb, const char* mnem, uint8_t op0, uint8_t op1, size_t label_idx) +// dec - Decrement integer by 1 +void dec(codeblock_t* cb, x86opnd_t opnd) { - //cb.writeASM(mnem, label); + write_rm_unary( + cb, + "dec", + 0xFE, // opMemReg8 + 0xFF, // opMemRegPref + 0x01, // opExt + opnd + ); +} - // Write the opcode - cb_write_byte(cb, op0); - cb_write_byte(cb, op1); +/* +// div - Unsigned integer division +alias div = writeRMUnary!( + "div", + 0xF6, // opMemReg8 + 0xF7, // opMemRegPref + 0x06 // opExt +); +*/ - // Add a reference to the label - cb_label_ref(cb, label_idx); +/* +/// divsd - Divide scalar double +alias divsd = writeXMM64!( + "divsd", + 0xF2, // prefix + 0x0F, // opRegMem0 + 0x5E // opRegMem1 +); +*/ - // Relative 32-bit offset to be patched - cb_write_int(cb, 0, 32); +/* +// idiv - Signed integer division +alias idiv = writeRMUnary!( + "idiv", + 0xF6, // opMemReg8 + 0xF7, // opMemRegPref + 0x07 // opExt +); +*/ + +/* +/// imul - Signed integer multiplication with two operands +void imul(CodeBlock cb, X86Opnd opnd0, X86Opnd opnd1) +{ + cb.writeASM("imul", opnd0, opnd1); + + assert (opnd0.isReg, "invalid first operand"); + auto opndSize = opnd0.reg.size; + + // Check the size of opnd1 + if (opnd1.isReg) + assert (opnd1.reg.size is opndSize, "operand size mismatch"); + else if (opnd1.isMem) + assert (opnd1.mem.size is opndSize, "operand size mismatch"); + + assert (opndSize is 16 || opndSize is 32 || opndSize is 64); + auto szPref = opndSize is 16; + auto rexW = opndSize is 64; + + cb.writeRMInstr!('r', 0xFF, 0x0F, 0xAF)(szPref, rexW, opnd0, opnd1); +} +*/ + +/* +/// imul - Signed integer multiplication with three operands (one immediate) +void imul(CodeBlock cb, X86Opnd opnd0, X86Opnd opnd1, X86Opnd opnd2) +{ + cb.writeASM("imul", opnd0, opnd1, opnd2); + + assert (opnd0.isReg, "invalid first operand"); + auto opndSize = opnd0.reg.size; + + // Check the size of opnd1 + if (opnd1.isReg) + assert (opnd1.reg.size is opndSize, "operand size mismatch"); + else if (opnd1.isMem) + assert (opnd1.mem.size is opndSize, "operand size mismatch"); + + assert (opndSize is 16 || opndSize is 32 || opndSize is 64); + auto szPref = opndSize is 16; + auto rexW = opndSize is 64; + + assert (opnd2.isImm, "invalid third operand"); + auto imm = opnd2.imm; + + // 8-bit immediate + if (imm.immSize <= 8) + { + cb.writeRMInstr!('r', 0xFF, 0x6B)(szPref, rexW, opnd0, opnd1); + cb.writeInt(imm.imm, 8); + } + + // 32-bit immediate + else if (imm.immSize <= 32) + { + assert (imm.immSize <= opndSize, "immediate too large for dst"); + cb.writeRMInstr!('r', 0xFF, 0x69)(szPref, rexW, opnd0, opnd1); + cb.writeInt(imm.imm, min(opndSize, 32)); + } + + // Immediate too large + else + { + assert (false, "immediate value too large"); + } +} +*/ + +// inc - Increment integer by 1 +void inc(codeblock_t* cb, x86opnd_t opnd) +{ + write_rm_unary( + cb, + "inc", + 0xFE, // opMemReg8 + 0xFF, // opMemRegPref + 0x00, // opExt + opnd + ); } /// jcc - Conditional relative jump to a label diff --git a/ujit_asm.h b/ujit_asm.h index 339027d726..da249abf65 100644 --- a/ujit_asm.h +++ b/ujit_asm.h @@ -196,6 +196,8 @@ void cb_write_epilogue(codeblock_t* cb); https://github.com/ruby/ruby/blob/trunk/ujit_asm.h#L196 void add(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 dec(codeblock_t* cb, x86opnd_t opnd); +void inc(codeblock_t* cb, x86opnd_t opnd); void ja(codeblock_t* cb, size_t label_idx); void jae(codeblock_t* cb, size_t label_idx); void jb(codeblock_t* cb, size_t label_idx); diff --git a/ujit_asm_tests.c b/ujit_asm_tests.c index 8f93f8fefe..4d2ed9cff4 100644 --- a/ujit_asm_tests.c +++ b/ujit_asm_tests.c @@ -93,6 +93,38 @@ void run_tests() https://github.com/ruby/ruby/blob/trunk/ujit_asm_tests.c#L93 cb_set_pos(cb, 0); call(cb, RAX); check_bytes(cb, "FFD0"); cb_set_pos(cb, 0); call(cb, mem_opnd(64, RSP, 8)); check_bytes(cb, "FF542408"); + // dec + /* + test( + delegate void (CodeBlock cb) { cb.dec(X86Opnd(CX)); }, + "66FFC9" + ); + */ + cb_set_pos(cb, 0); dec(cb, EDX); check_bytes(cb, "FFCA"); + + // div + /* + test( + delegate void (CodeBlock cb) { cb.div(X86Opnd(EDX)); }, + "F7F2" + ); + test( + delegate void (CodeBlock cb) { cb.div(X86Opnd(32, RSP, -12)); }, + "F77424F4" + ); + */ + + // inc + /* + test( + delegate void (CodeBlock cb) { cb.inc(X86Opnd(BL)); }, + "FEC3" + ); + */ + cb_set_pos(cb, 0); inc(cb, ESP); check_bytes(cb, "FFC4"); + cb_set_pos(cb, 0); inc(cb, mem_opnd(32, RSP, 0)); check_bytes(cb, "FF0424"); + cb_set_pos(cb, 0); inc(cb, mem_opnd(64, RSP, 4)); check_bytes(cb, "48FF442404"); + // jcc { cb_set_pos(cb, 0); diff --git a/ujit_compile.c b/ujit_compile.c index 60439e7260..bc49d63fee 100644 --- a/ujit_compile.c +++ b/ujit_compile.c @@ -47,7 +47,7 @@ ujit_compile_insn(rb_iseq_t *iseq, size_t insn_idx) https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L47 //printf("%s\n", name); // TODO: encode individual instructions, eg - // putnil, putobject, pop, dup, getlocal, nilp + // nop, putnil, putobject, putself, pop, dup, getlocal, nilp if (insn == BIN(pop)) { -- cgit v1.2.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/