Browse Source

Make loop, loopz, loopnz and jcxz custom generated

Fabian 3 years ago
parent
commit
a73988a817

+ 7 - 3
gen/generate_analyzer.js

@@ -284,9 +284,13 @@ function gen_instruction_body_after_fixed_g(encoding, size)
 
                 if(encoding.conditional_jump)
                 {
-                    console.assert((encoding.opcode & ~0xF) === 0x70 || (encoding.opcode & ~0xF) === 0x0F80);
-                    const condition_index = encoding.opcode & 0xF;
-                    body.push(`analysis.ty = ::analysis::AnalysisType::Jump { offset: jump_offset as i32, condition: Some(${condition_index}), is_32: cpu.osize_32() };`);
+                    console.assert(
+                        (encoding.opcode & ~0xF) === 0x70 ||
+                        (encoding.opcode & ~0xF) === 0x0F80 ||
+                        (encoding.opcode & ~0x3) === 0xE0
+                    );
+                    const condition_index = encoding.opcode & 0xFF;
+                    body.push(`analysis.ty = ::analysis::AnalysisType::Jump { offset: jump_offset as i32, condition: Some(0x${hex(condition_index, 2)}), is_32: cpu.osize_32() };`);
                 }
                 else
                 {

+ 4 - 6
gen/x86_table.js

@@ -345,12 +345,10 @@ const encodings = [
     { opcode: 0xDF, e: 1, fixed_g: 7, custom: 1, is_fpu: 1, task_switch_test: 1, },
 
     // loop, jcxz, etc.
-    // Conditional jumps, but condition code not supported by code generator
-    // (these are never generated by modern compilers)
-    { opcode: 0xE0, os: 1, imm8s: 1, skip: 1, block_boundary: 1, /* jump_offset_imm: 1, conditional_jump: 1, */ },
-    { opcode: 0xE1, os: 1, imm8s: 1, skip: 1, block_boundary: 1, /* jump_offset_imm: 1, conditional_jump: 1, */ },
-    { opcode: 0xE2, os: 1, imm8s: 1, skip: 1, block_boundary: 1, /* jump_offset_imm: 1, conditional_jump: 1, */ },
-    { opcode: 0xE3, os: 1, imm8s: 1, skip: 1, block_boundary: 1, /* jump_offset_imm: 1, conditional_jump: 1, */ },
+    { opcode: 0xE0, os: 1, imm8s: 1, no_block_boundary_in_interpreted: 1, skip: 1, block_boundary: 1, jump_offset_imm: 1, custom: 1, conditional_jump: 1, },
+    { opcode: 0xE1, os: 1, imm8s: 1, no_block_boundary_in_interpreted: 1, skip: 1, block_boundary: 1, jump_offset_imm: 1, custom: 1, conditional_jump: 1, },
+    { opcode: 0xE2, os: 1, imm8s: 1, no_block_boundary_in_interpreted: 1, skip: 1, block_boundary: 1, jump_offset_imm: 1, custom: 1, conditional_jump: 1, },
+    { opcode: 0xE3, os: 1, imm8s: 1, no_block_boundary_in_interpreted: 1, skip: 1, block_boundary: 1, jump_offset_imm: 1, custom: 1, conditional_jump: 1, },
 
     // port functions aren't jumps, but they may modify eip due to how they are implemented
     { opcode: 0xE4, block_boundary: 1, imm8: 1, skip: 1, }, // in

+ 85 - 24
src/rust/codegen.rs

@@ -1601,6 +1601,49 @@ pub fn gen_test_be(builder: &mut WasmBuilder) {
     builder.instruction_body.or_i32();
 }
 
+pub fn gen_test_loopnz(ctx: &mut JitContext, is_asize_32: bool) {
+    gen_test_loop(ctx, is_asize_32);
+    ctx.builder.instruction_body.eqz_i32();
+    gen_getzf(&mut ctx.builder);
+    ctx.builder.instruction_body.or_i32();
+    ctx.builder.instruction_body.eqz_i32();
+}
+pub fn gen_test_loopz(ctx: &mut JitContext, is_asize_32: bool) {
+    gen_test_loop(ctx, is_asize_32);
+    ctx.builder.instruction_body.eqz_i32();
+    gen_getzf(&mut ctx.builder);
+    ctx.builder.instruction_body.eqz_i32();
+    ctx.builder.instruction_body.or_i32();
+    ctx.builder.instruction_body.eqz_i32();
+}
+pub fn gen_test_loop(ctx: &mut JitContext, is_asize_32: bool) {
+    if is_asize_32 {
+        gen_get_reg32(ctx, regs::ECX);
+    }
+    else {
+        gen_get_reg16(ctx, regs::CX);
+    }
+    ctx.builder.instruction_body.const_i32(1);
+    ctx.builder.instruction_body.sub_i32();
+    if is_asize_32 {
+        gen_set_reg32(ctx, regs::ECX);
+        gen_get_reg32(ctx, regs::ECX);
+    }
+    else {
+        gen_set_reg16(ctx, regs::ECX);
+        gen_get_reg16(ctx, regs::CX);
+    }
+}
+pub fn gen_test_jcxz(ctx: &mut JitContext, is_asize_32: bool) {
+    if is_asize_32 {
+        gen_get_reg32(ctx, regs::ECX);
+    }
+    else {
+        gen_get_reg16(ctx, regs::CX);
+    }
+    ctx.builder.instruction_body.eqz_i32();
+}
+
 pub fn gen_fpu_get_sti(ctx: &mut JitContext, i: u32) {
     ctx.builder.instruction_body.const_i32(i as i32);
     gen_call_fn1_ret_f64(ctx.builder, "fpu_get_sti");
@@ -1641,32 +1684,50 @@ pub fn gen_trigger_gp(ctx: &mut JitContext, error_code: u32) {
     ctx.builder.instruction_body.return_();
 }
 
-pub fn gen_condition_fn(builder: &mut WasmBuilder, condition: u8) {
-    dbg_assert!(condition < 16);
-    if condition == 2 {
-        gen_getcf(builder);
-    }
-    else if condition == 3 {
-        gen_getcf(builder);
-        builder.instruction_body.eqz_i32();
-    }
-    else if condition == 4 {
-        gen_getzf(builder);
-    }
-    else if condition == 5 {
-        gen_getzf(builder);
-        builder.instruction_body.eqz_i32();
-    }
-    else if condition == 6 {
-        gen_test_be(builder);
-    }
-    else if condition == 7 {
-        gen_test_be(builder);
-        builder.instruction_body.eqz_i32();
+pub fn gen_condition_fn(ctx: &mut JitContext, mut condition: u8) {
+    if condition & 0xF0 == 0x00 || condition & 0xF0 == 0x70 || condition & 0xF0 == 0x80 {
+        condition &= 0xF;
+        if condition == 2 {
+            gen_getcf(ctx.builder);
+        }
+        else if condition == 3 {
+            gen_getcf(ctx.builder);
+            ctx.builder.instruction_body.eqz_i32();
+        }
+        else if condition == 4 {
+            gen_getzf(ctx.builder);
+        }
+        else if condition == 5 {
+            gen_getzf(ctx.builder);
+            ctx.builder.instruction_body.eqz_i32();
+        }
+        else if condition == 6 {
+            gen_test_be(ctx.builder);
+        }
+        else if condition == 7 {
+            gen_test_be(ctx.builder);
+            ctx.builder.instruction_body.eqz_i32();
+        }
+        else {
+            let condition_name = CONDITION_FUNCTIONS[condition as usize];
+            gen_fn0_const_ret(ctx.builder, condition_name);
+        }
     }
     else {
-        let condition_name = CONDITION_FUNCTIONS[condition as usize];
-        gen_fn0_const_ret(builder, condition_name);
+        // loop, loopnz, loopz, jcxz
+        dbg_assert!(condition & !0x3 == 0xE0);
+        if condition == 0xE0 {
+            gen_test_loopnz(ctx, ctx.cpu.asize_32());
+        }
+        else if condition == 0xE1 {
+            gen_test_loopz(ctx, ctx.cpu.asize_32());
+        }
+        else if condition == 0xE2 {
+            gen_test_loop(ctx, ctx.cpu.asize_32());
+        }
+        else if condition == 0xE3 {
+            gen_test_jcxz(ctx, ctx.cpu.asize_32());
+        }
     }
 }
 

+ 2 - 2
src/rust/jit.rs

@@ -1106,9 +1106,9 @@ fn jit_generate_module(
                 jump_offset_is_32,
             } => {
                 // Conditional jump to next basic block
-                // - jnz, jc, etc.
+                // - jnz, jc, loop, jcxz, etc.
 
-                codegen::gen_condition_fn(ctx.builder, condition);
+                codegen::gen_condition_fn(ctx, condition);
                 ctx.builder.instruction_body.if_void();
 
                 // Branch taken

+ 15 - 6
src/rust/jit_instructions.rs

@@ -1526,6 +1526,15 @@ pub fn instr32_7E_jit(_ctx: &mut JitContext, _imm: u32) {}
 pub fn instr16_7F_jit(_ctx: &mut JitContext, _imm: u32) {}
 pub fn instr32_7F_jit(_ctx: &mut JitContext, _imm: u32) {}
 
+pub fn instr16_E0_jit(_ctx: &mut JitContext, _imm: u32) {}
+pub fn instr32_E0_jit(_ctx: &mut JitContext, _imm: u32) {}
+pub fn instr16_E1_jit(_ctx: &mut JitContext, _imm: u32) {}
+pub fn instr32_E1_jit(_ctx: &mut JitContext, _imm: u32) {}
+pub fn instr16_E2_jit(_ctx: &mut JitContext, _imm: u32) {}
+pub fn instr32_E2_jit(_ctx: &mut JitContext, _imm: u32) {}
+pub fn instr16_E3_jit(_ctx: &mut JitContext, _imm: u32) {}
+pub fn instr32_E3_jit(_ctx: &mut JitContext, _imm: u32) {}
+
 define_instruction_read_write_mem8!("add8", instr_80_0_mem_jit, instr_80_0_reg_jit, imm8);
 define_instruction_read_write_mem8!("or8", instr_80_1_mem_jit, instr_80_1_reg_jit, imm8);
 define_instruction_read_write_mem8!("adc8", instr_80_2_mem_jit, instr_80_2_reg_jit, imm8);
@@ -3567,7 +3576,7 @@ macro_rules! define_cmovcc16(
         pub fn $name_mem(ctx: &mut JitContext, modrm_byte: u8, r: u32) {
             codegen::gen_modrm_resolve_safe_read16(ctx, modrm_byte);
             let value = ctx.builder.set_new_local();
-            codegen::gen_condition_fn(ctx.builder, $cond);
+            codegen::gen_condition_fn(ctx, $cond);
             ctx.builder.instruction_body.if_void();
             ctx.builder.instruction_body.get_local(&value);
             codegen::gen_set_reg16(ctx, r);
@@ -3576,7 +3585,7 @@ macro_rules! define_cmovcc16(
         }
 
         pub fn $name_reg(ctx: &mut JitContext, r1: u32, r2: u32) {
-            codegen::gen_condition_fn(ctx.builder, $cond);
+            codegen::gen_condition_fn(ctx, $cond);
             ctx.builder.instruction_body.if_void();
             codegen::gen_get_reg16(ctx, r1);
             codegen::gen_set_reg16(ctx, r2);
@@ -3590,7 +3599,7 @@ macro_rules! define_cmovcc32(
         pub fn $name_mem(ctx: &mut JitContext, modrm_byte: u8, r: u32) {
             codegen::gen_modrm_resolve_safe_read32(ctx, modrm_byte);
             let value = ctx.builder.set_new_local();
-            codegen::gen_condition_fn(ctx.builder, $cond);
+            codegen::gen_condition_fn(ctx, $cond);
             ctx.builder.instruction_body.if_void();
             ctx.builder.instruction_body.get_local(&value);
             codegen::gen_set_reg32(ctx, r);
@@ -3599,7 +3608,7 @@ macro_rules! define_cmovcc32(
         }
 
         pub fn $name_reg(ctx: &mut JitContext, r1: u32, r2: u32) {
-            codegen::gen_condition_fn(ctx.builder, $cond);
+            codegen::gen_condition_fn(ctx, $cond);
             ctx.builder.instruction_body.if_void();
             codegen::gen_get_reg32(ctx, r1);
             codegen::gen_set_reg32(ctx, r2);
@@ -3649,7 +3658,7 @@ macro_rules! define_setcc(
         pub fn $name_mem(ctx: &mut JitContext, modrm_byte: u8, _r: u32) {
             codegen::gen_modrm_resolve(ctx, modrm_byte);
             let address_local = ctx.builder.set_new_local();
-            codegen::gen_condition_fn(&mut ctx.builder, $cond);
+            codegen::gen_condition_fn(ctx, $cond);
             ctx.builder.instruction_body.const_i32(0);
             ctx.builder.instruction_body.ne_i32();
             let value_local = ctx.builder.set_new_local();
@@ -3659,7 +3668,7 @@ macro_rules! define_setcc(
         }
 
         pub fn $name_reg(ctx: &mut JitContext, r1: u32, _r2: u32) {
-            codegen::gen_condition_fn(&mut ctx.builder, $cond);
+            codegen::gen_condition_fn(ctx, $cond);
             ctx.builder.instruction_body.const_i32(0);
             ctx.builder.instruction_body.ne_i32();
             codegen::gen_set_reg8(ctx, r1);

+ 25 - 0
tests/nasm/jcxz.asm

@@ -0,0 +1,25 @@
+global _start
+
+%include "header.inc"
+
+    mov ecx, 0x10000
+    jecxz cont1
+    or eax, 1
+cont1:
+
+    mov ecx, 0
+    jecxz cont2
+    or eax, 2
+cont2:
+
+    mov ecx, 0x1
+    jcxz cont3
+    or eax, 4
+cont3:
+
+    mov ecx, 0x10000
+    jcxz cont4
+    or eax, 8
+cont4:
+
+%include "footer.inc"

+ 18 - 0
tests/nasm/loop.asm

@@ -0,0 +1,18 @@
+global _start
+
+%include "header.inc"
+
+    mov ecx, 0x10042
+    mov eax, 0
+start1:
+    inc eax
+    loop start1
+
+    mov ecx, 0x10005
+    mov ebx, 0
+start2:
+    inc ebx
+    db 67h
+    loop start2
+
+%include "footer.inc"

+ 24 - 0
tests/nasm/loopnz.asm

@@ -0,0 +1,24 @@
+global _start
+
+%include "header.inc"
+
+    mov ecx, 0x10042
+    mov eax, 42
+start1:
+    dec eax
+    loopz start1
+
+    mov ecx, 0x10005
+    mov ebx, 51
+start2:
+    dec ebx
+    db 67h
+    loopz start2
+
+    mov ecx, 0x10005
+start3:
+    or edx, 1
+    db 67h
+    loopz start3
+
+%include "footer.inc"

+ 24 - 0
tests/nasm/loopz.asm

@@ -0,0 +1,24 @@
+global _start
+
+%include "header.inc"
+
+    mov ecx, 0x10042
+    mov eax, -1
+start1:
+    inc eax
+    loopz start1
+
+    mov ecx, 0x10005
+    mov ebx, -1
+start2:
+    inc ebx
+    db 67h
+    loopz start2
+
+    mov ecx, 0x10005
+start3:
+    xor edx, edx
+    db 67h
+    loopz start3
+
+%include "footer.inc"