Refactor modrm decoding for jit
This commit is contained in:
parent
9ccef87b88
commit
ab46fe4f37
|
@ -291,7 +291,7 @@ function gen_instruction_body_after_fixed_g(encoding, size)
|
|||
}
|
||||
else if(encoding.custom)
|
||||
{
|
||||
const mem_args = ["ctx", "modrm_byte"];
|
||||
const mem_args = ["ctx", "addr"];
|
||||
const reg_args = ["ctx", "(modrm_byte & 7) as u32"];
|
||||
|
||||
if(encoding.fixed_g === undefined)
|
||||
|
@ -315,6 +315,7 @@ function gen_instruction_body_after_fixed_g(encoding, size)
|
|||
// Note: Custom function is responsible for calling
|
||||
// the proper read_imm function after calling
|
||||
// gen_modrm_resolve
|
||||
"let addr = ::modrm::decode(ctx.cpu, modrm_byte);",
|
||||
gen_call(`::jit_instructions::${instruction_name}_mem_jit`, mem_args),
|
||||
mem_postfix
|
||||
),
|
||||
|
@ -354,7 +355,8 @@ function gen_instruction_body_after_fixed_g(encoding, size)
|
|||
if_blocks: [{
|
||||
condition: "modrm_byte < 0xC0",
|
||||
body: [].concat(
|
||||
gen_call(`::codegen::gen_modrm_resolve`, ["ctx", "modrm_byte"]),
|
||||
"let addr = ::modrm::decode(ctx.cpu, modrm_byte);",
|
||||
gen_call(`::codegen::gen_modrm_resolve`, ["ctx", "addr"]),
|
||||
imm_read_bindings,
|
||||
gen_call(`::codegen::gen_modrm_fn${mem_args.length - 2}`, mem_args),
|
||||
mem_postfix
|
||||
|
|
|
@ -7,6 +7,7 @@ use cpu2::memory;
|
|||
use global_pointers;
|
||||
use jit::JitContext;
|
||||
use modrm;
|
||||
use modrm::ModrmByte;
|
||||
use profiler;
|
||||
use regs;
|
||||
use wasmgen::wasm_builder::{WasmBuilder, WasmLocal, WasmLocalI64};
|
||||
|
@ -310,7 +311,9 @@ pub fn gen_modrm_fn2(builder: &mut WasmBuilder, name: &str, arg0: u32, arg1: u32
|
|||
builder.call_fn3(name);
|
||||
}
|
||||
|
||||
pub fn gen_modrm_resolve(ctx: &mut JitContext, modrm_byte: u8) { modrm::gen(ctx, modrm_byte) }
|
||||
pub fn gen_modrm_resolve(ctx: &mut JitContext, modrm_byte: ModrmByte) {
|
||||
modrm::gen(ctx, modrm_byte)
|
||||
}
|
||||
|
||||
pub fn gen_set_reg8_r(ctx: &mut JitContext, dest: u32, src: u32) {
|
||||
// generates: reg8[r_dest] = reg8[r_src]
|
||||
|
@ -328,31 +331,35 @@ pub fn gen_set_reg32_r(ctx: &mut JitContext, dest: u32, src: u32) {
|
|||
gen_set_reg32(ctx, dest);
|
||||
}
|
||||
|
||||
pub fn gen_modrm_resolve_safe_read8(ctx: &mut JitContext, modrm_byte: u8) {
|
||||
pub fn gen_modrm_resolve_safe_read8(ctx: &mut JitContext, modrm_byte: ModrmByte) {
|
||||
gen_modrm_resolve(ctx, modrm_byte);
|
||||
let address_local = ctx.builder.set_new_local();
|
||||
gen_safe_read8(ctx, &address_local);
|
||||
ctx.builder.free_local(address_local);
|
||||
}
|
||||
pub fn gen_modrm_resolve_safe_read16(ctx: &mut JitContext, modrm_byte: u8) {
|
||||
pub fn gen_modrm_resolve_safe_read16(ctx: &mut JitContext, modrm_byte: ModrmByte) {
|
||||
gen_modrm_resolve(ctx, modrm_byte);
|
||||
let address_local = ctx.builder.set_new_local();
|
||||
gen_safe_read16(ctx, &address_local);
|
||||
ctx.builder.free_local(address_local);
|
||||
}
|
||||
pub fn gen_modrm_resolve_safe_read32(ctx: &mut JitContext, modrm_byte: u8) {
|
||||
pub fn gen_modrm_resolve_safe_read32(ctx: &mut JitContext, modrm_byte: ModrmByte) {
|
||||
gen_modrm_resolve(ctx, modrm_byte);
|
||||
let address_local = ctx.builder.set_new_local();
|
||||
gen_safe_read32(ctx, &address_local);
|
||||
ctx.builder.free_local(address_local);
|
||||
}
|
||||
pub fn gen_modrm_resolve_safe_read64(ctx: &mut JitContext, modrm_byte: u8) {
|
||||
pub fn gen_modrm_resolve_safe_read64(ctx: &mut JitContext, modrm_byte: ModrmByte) {
|
||||
gen_modrm_resolve(ctx, modrm_byte);
|
||||
let address_local = ctx.builder.set_new_local();
|
||||
gen_safe_read64(ctx, &address_local);
|
||||
ctx.builder.free_local(address_local);
|
||||
}
|
||||
pub fn gen_modrm_resolve_safe_read128(ctx: &mut JitContext, modrm_byte: u8, where_to_write: u32) {
|
||||
pub fn gen_modrm_resolve_safe_read128(
|
||||
ctx: &mut JitContext,
|
||||
modrm_byte: ModrmByte,
|
||||
where_to_write: u32,
|
||||
) {
|
||||
gen_modrm_resolve(ctx, modrm_byte);
|
||||
let address_local = ctx.builder.set_new_local();
|
||||
gen_safe_read128(ctx, &address_local, where_to_write);
|
||||
|
@ -1522,13 +1529,13 @@ pub fn gen_fpu_get_sti(ctx: &mut JitContext, i: u32) {
|
|||
ctx.builder.call_fn1_ret_f64("fpu_get_sti");
|
||||
}
|
||||
|
||||
pub fn gen_fpu_load_m32(ctx: &mut JitContext, modrm_byte: u8) {
|
||||
pub fn gen_fpu_load_m32(ctx: &mut JitContext, modrm_byte: ModrmByte) {
|
||||
gen_modrm_resolve_safe_read32(ctx, modrm_byte);
|
||||
ctx.builder.reinterpret_i32_as_f32();
|
||||
ctx.builder.promote_f32_to_f64();
|
||||
}
|
||||
|
||||
pub fn gen_fpu_load_m64(ctx: &mut JitContext, modrm_byte: u8) {
|
||||
pub fn gen_fpu_load_m64(ctx: &mut JitContext, modrm_byte: ModrmByte) {
|
||||
gen_modrm_resolve_safe_read64(ctx, modrm_byte);
|
||||
ctx.builder.reinterpret_i64_as_f64();
|
||||
}
|
||||
|
|
|
@ -11,10 +11,6 @@ pub struct CpuContext {
|
|||
}
|
||||
|
||||
impl CpuContext {
|
||||
pub fn advance8(&mut self) {
|
||||
dbg_assert!(self.eip & 0xFFF < 0xFFF);
|
||||
self.eip += 1;
|
||||
}
|
||||
pub fn advance16(&mut self) {
|
||||
dbg_assert!(self.eip & 0xFFF < 0xFFE);
|
||||
self.eip += 2;
|
||||
|
@ -41,7 +37,6 @@ impl CpuContext {
|
|||
self.eip += 2;
|
||||
v
|
||||
}
|
||||
pub fn read_imm16s(&mut self) -> i16 { self.read_imm16() as i16 }
|
||||
pub fn read_imm32(&mut self) -> u32 {
|
||||
dbg_assert!(self.eip & 0xFFF < 0xFFC);
|
||||
let v = memory::read32s(self.eip) as u32;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -8,157 +8,230 @@ use regs::{BP, BX, DI, SI};
|
|||
use regs::{CS, DS, SS};
|
||||
use regs::{EAX, EBP, EBX, ECX, EDI, EDX, ESI, ESP};
|
||||
|
||||
pub fn skip(ctx: &mut CpuContext, modrm_byte: u8) {
|
||||
if ctx.asize_32() { skip32(ctx, modrm_byte) } else { skip16(ctx, modrm_byte) }
|
||||
pub struct ModrmByte {
|
||||
segment: u32,
|
||||
first_reg: Option<u32>,
|
||||
second_reg: Option<u32>,
|
||||
shift: u8,
|
||||
immediate: i32,
|
||||
is_16: bool,
|
||||
}
|
||||
|
||||
fn skip16(ctx: &mut CpuContext, modrm_byte: u8) {
|
||||
dbg_assert!(modrm_byte < 0xC0);
|
||||
let r = modrm_byte & 7;
|
||||
pub fn decode(ctx: &mut CpuContext, modrm_byte: u8) -> ModrmByte {
|
||||
if ctx.asize_32() { decode32(ctx, modrm_byte) } else { decode16(ctx, modrm_byte) }
|
||||
}
|
||||
|
||||
if modrm_byte < 0x40 {
|
||||
if r == 6 {
|
||||
ctx.advance16()
|
||||
fn decode16(ctx: &mut CpuContext, modrm_byte: u8) -> ModrmByte {
|
||||
fn mk16(
|
||||
segment: u32,
|
||||
first_reg: Option<u32>,
|
||||
second_reg: Option<u32>,
|
||||
immediate: i32,
|
||||
) -> ModrmByte {
|
||||
ModrmByte {
|
||||
segment,
|
||||
first_reg,
|
||||
second_reg,
|
||||
shift: 0,
|
||||
immediate,
|
||||
is_16: true,
|
||||
}
|
||||
}
|
||||
else if modrm_byte < 0x80 {
|
||||
ctx.advance8()
|
||||
}
|
||||
else {
|
||||
ctx.advance16()
|
||||
|
||||
match modrm_byte & !0o070 {
|
||||
0o000 => mk16(DS, Some(BX), Some(SI), 0),
|
||||
0o001 => mk16(DS, Some(BX), Some(DI), 0),
|
||||
0o002 => mk16(SS, Some(BP), Some(SI), 0),
|
||||
0o003 => mk16(SS, Some(BP), Some(DI), 0),
|
||||
0o004 => mk16(DS, Some(SI), None, 0),
|
||||
0o005 => mk16(DS, Some(DI), None, 0),
|
||||
0o006 => mk16(DS, None, None, ctx.read_imm16() as i32),
|
||||
0o007 => mk16(DS, Some(BX), None, 0),
|
||||
|
||||
0o100 => mk16(DS, Some(BX), Some(SI), ctx.read_imm8s() as i32),
|
||||
0o101 => mk16(DS, Some(BX), Some(DI), ctx.read_imm8s() as i32),
|
||||
0o102 => mk16(SS, Some(BP), Some(SI), ctx.read_imm8s() as i32),
|
||||
0o103 => mk16(SS, Some(BP), Some(DI), ctx.read_imm8s() as i32),
|
||||
0o104 => mk16(DS, Some(SI), None, ctx.read_imm8s() as i32),
|
||||
0o105 => mk16(DS, Some(DI), None, ctx.read_imm8s() as i32),
|
||||
0o106 => mk16(SS, Some(BP), None, ctx.read_imm8s() as i32),
|
||||
0o107 => mk16(DS, Some(BX), None, ctx.read_imm8s() as i32),
|
||||
|
||||
0o200 => mk16(DS, Some(BX), Some(SI), ctx.read_imm16() as i32),
|
||||
0o201 => mk16(DS, Some(BX), Some(DI), ctx.read_imm16() as i32),
|
||||
0o202 => mk16(SS, Some(BP), Some(SI), ctx.read_imm16() as i32),
|
||||
0o203 => mk16(SS, Some(BP), Some(DI), ctx.read_imm16() as i32),
|
||||
0o204 => mk16(DS, Some(SI), None, ctx.read_imm16() as i32),
|
||||
0o205 => mk16(DS, Some(DI), None, ctx.read_imm16() as i32),
|
||||
0o206 => mk16(SS, Some(BP), None, ctx.read_imm16() as i32),
|
||||
0o207 => mk16(DS, Some(BX), None, ctx.read_imm16() as i32),
|
||||
|
||||
_ => panic!("modrm byte >= 0xC0"),
|
||||
}
|
||||
}
|
||||
|
||||
fn skip32(ctx: &mut CpuContext, modrm_byte: u8) {
|
||||
dbg_assert!(modrm_byte < 0xC0);
|
||||
let r = modrm_byte & 7;
|
||||
fn decode32(ctx: &mut CpuContext, modrm_byte: u8) -> ModrmByte {
|
||||
fn mk32(segment: u32, first_reg: Option<u32>, immediate: i32) -> ModrmByte {
|
||||
ModrmByte {
|
||||
segment,
|
||||
first_reg,
|
||||
second_reg: None,
|
||||
shift: 0,
|
||||
immediate,
|
||||
is_16: false,
|
||||
}
|
||||
}
|
||||
|
||||
match modrm_byte & !0o070 {
|
||||
0o000 => mk32(DS, Some(EAX), 0),
|
||||
0o001 => mk32(DS, Some(ECX), 0),
|
||||
0o002 => mk32(DS, Some(EDX), 0),
|
||||
0o003 => mk32(DS, Some(EBX), 0),
|
||||
0o004 => decode_sib(ctx, Imm32::None),
|
||||
0o005 => mk32(DS, None, ctx.read_imm32() as i32),
|
||||
0o006 => mk32(DS, Some(ESI), 0),
|
||||
0o007 => mk32(DS, Some(EDI), 0),
|
||||
|
||||
0o100 => mk32(DS, Some(EAX), ctx.read_imm8s() as i32),
|
||||
0o101 => mk32(DS, Some(ECX), ctx.read_imm8s() as i32),
|
||||
0o102 => mk32(DS, Some(EDX), ctx.read_imm8s() as i32),
|
||||
0o103 => mk32(DS, Some(EBX), ctx.read_imm8s() as i32),
|
||||
0o104 => decode_sib(ctx, Imm32::Imm8),
|
||||
0o105 => mk32(SS, Some(EBP), ctx.read_imm8s() as i32),
|
||||
0o106 => mk32(DS, Some(ESI), ctx.read_imm8s() as i32),
|
||||
0o107 => mk32(DS, Some(EDI), ctx.read_imm8s() as i32),
|
||||
|
||||
0o200 => mk32(DS, Some(EAX), ctx.read_imm32() as i32),
|
||||
0o201 => mk32(DS, Some(ECX), ctx.read_imm32() as i32),
|
||||
0o202 => mk32(DS, Some(EDX), ctx.read_imm32() as i32),
|
||||
0o203 => mk32(DS, Some(EBX), ctx.read_imm32() as i32),
|
||||
0o204 => decode_sib(ctx, Imm32::Imm32),
|
||||
0o205 => mk32(SS, Some(EBP), ctx.read_imm32() as i32),
|
||||
0o206 => mk32(DS, Some(ESI), ctx.read_imm32() as i32),
|
||||
0o207 => mk32(DS, Some(EDI), ctx.read_imm32() as i32),
|
||||
|
||||
_ => panic!("modrm byte >= 0xC0"),
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_sib(ctx: &mut CpuContext, immediate: Imm32) -> ModrmByte {
|
||||
let sib_byte = ctx.read_imm8();
|
||||
let r = sib_byte & 7;
|
||||
let m = sib_byte >> 3 & 7;
|
||||
let shift = sib_byte >> 6 & 3;
|
||||
|
||||
let second_reg = if m == 4 { None } else { Some(m as u32) };
|
||||
|
||||
let segment;
|
||||
let reg;
|
||||
|
||||
if r == 4 {
|
||||
let sib = ctx.read_imm8();
|
||||
if modrm_byte < 0x40 {
|
||||
if sib & 7 == 5 {
|
||||
ctx.advance32()
|
||||
}
|
||||
}
|
||||
else if modrm_byte < 0x80 {
|
||||
ctx.advance8()
|
||||
segment = SS;
|
||||
reg = ESP;
|
||||
}
|
||||
else if r == 5 {
|
||||
if immediate == Imm32::None {
|
||||
return ModrmByte {
|
||||
segment: DS,
|
||||
first_reg: None,
|
||||
second_reg,
|
||||
shift,
|
||||
immediate: ctx.read_imm32() as i32,
|
||||
is_16: false,
|
||||
};
|
||||
}
|
||||
else {
|
||||
ctx.advance32()
|
||||
segment = SS;
|
||||
reg = EBP;
|
||||
}
|
||||
}
|
||||
else if r == 5 && modrm_byte < 0x40 {
|
||||
ctx.advance32();
|
||||
}
|
||||
else {
|
||||
if modrm_byte < 0x40 {
|
||||
// Nothing
|
||||
}
|
||||
else if modrm_byte < 0x80 {
|
||||
ctx.advance8()
|
||||
}
|
||||
else {
|
||||
ctx.advance32()
|
||||
}
|
||||
segment = DS;
|
||||
reg = r as u32;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen(ctx: &mut JitContext, modrm_byte: u8) {
|
||||
if ctx.cpu.asize_32() { gen32(ctx, modrm_byte) } else { gen16(ctx, modrm_byte) }
|
||||
}
|
||||
|
||||
enum Imm16 {
|
||||
None,
|
||||
Imm8,
|
||||
Imm16,
|
||||
}
|
||||
|
||||
enum Offset16 {
|
||||
Zero,
|
||||
One(u32),
|
||||
Two(u32, u32),
|
||||
}
|
||||
|
||||
fn gen16_case(ctx: &mut JitContext, seg: u32, offset: Offset16, imm: Imm16) {
|
||||
// Generates one of:
|
||||
// - add_segment(reg)
|
||||
// - add_segment(imm)
|
||||
// - add_segment(reg1 + reg2 & 0xFFFF)
|
||||
// - add_segment(reg1 + imm & 0xFFFF)
|
||||
// - add_segment(reg1 + reg2 + imm & 0xFFFF)
|
||||
|
||||
let immediate_value = match imm {
|
||||
Imm16::None => 0,
|
||||
Imm16::Imm8 => ctx.cpu.read_imm8s() as i32,
|
||||
Imm16::Imm16 => ctx.cpu.read_imm16s() as i32,
|
||||
let immediate = match immediate {
|
||||
Imm32::None => 0,
|
||||
Imm32::Imm8 => ctx.read_imm8s() as i32,
|
||||
Imm32::Imm32 => ctx.read_imm32() as i32,
|
||||
};
|
||||
|
||||
match offset {
|
||||
Offset16::Zero => {
|
||||
ctx.builder.const_i32(immediate_value & 0xFFFF);
|
||||
},
|
||||
Offset16::One(r) => {
|
||||
codegen::gen_get_reg16(ctx, r);
|
||||
ModrmByte {
|
||||
segment,
|
||||
first_reg: Some(reg),
|
||||
second_reg,
|
||||
shift,
|
||||
immediate,
|
||||
is_16: false,
|
||||
}
|
||||
}
|
||||
|
||||
if immediate_value != 0 {
|
||||
ctx.builder.const_i32(immediate_value);
|
||||
ctx.builder.add_i32();
|
||||
|
||||
ctx.builder.const_i32(0xFFFF);
|
||||
ctx.builder.and_i32();
|
||||
pub fn gen(ctx: &mut JitContext, modrm_byte: ModrmByte) {
|
||||
codegen::gen_profiler_stat_increment(
|
||||
ctx.builder,
|
||||
match modrm_byte {
|
||||
ModrmByte {
|
||||
first_reg: None,
|
||||
second_reg: None,
|
||||
..
|
||||
} => profiler::stat::MODRM_SIMPLE_CONST_OFFSET,
|
||||
ModrmByte {
|
||||
first_reg: Some(_),
|
||||
second_reg: None,
|
||||
..
|
||||
}
|
||||
| ModrmByte {
|
||||
first_reg: None,
|
||||
second_reg: Some(_),
|
||||
shift: 0,
|
||||
..
|
||||
} => {
|
||||
if modrm_byte.immediate == 0 {
|
||||
profiler::stat::MODRM_SIMPLE_REG
|
||||
}
|
||||
else {
|
||||
profiler::stat::MODRM_SIMPLE_REG_WITH_OFFSET
|
||||
}
|
||||
},
|
||||
_ => profiler::stat::MODRM_COMPLEX,
|
||||
},
|
||||
Offset16::Two(r1, r2) => {
|
||||
codegen::gen_get_reg16(ctx, r1);
|
||||
codegen::gen_get_reg16(ctx, r2);
|
||||
);
|
||||
|
||||
let mut have_something_on_stack = false;
|
||||
|
||||
if let Some(reg) = modrm_byte.first_reg {
|
||||
codegen::gen_get_reg32(ctx, reg);
|
||||
have_something_on_stack = true;
|
||||
}
|
||||
|
||||
if let Some(reg) = modrm_byte.second_reg {
|
||||
codegen::gen_get_reg32(ctx, reg);
|
||||
if modrm_byte.shift != 0 {
|
||||
ctx.builder.const_i32(modrm_byte.shift.into());
|
||||
ctx.builder.shl_i32();
|
||||
}
|
||||
if have_something_on_stack {
|
||||
ctx.builder.add_i32();
|
||||
|
||||
if immediate_value != 0 {
|
||||
ctx.builder.const_i32(immediate_value);
|
||||
ctx.builder.add_i32();
|
||||
}
|
||||
|
||||
ctx.builder.const_i32(0xFFFF);
|
||||
ctx.builder.and_i32();
|
||||
},
|
||||
}
|
||||
have_something_on_stack = true;
|
||||
}
|
||||
|
||||
jit_add_seg_offset(ctx, seg);
|
||||
}
|
||||
|
||||
fn gen16(ctx: &mut JitContext, modrm_byte: u8) {
|
||||
match modrm_byte & !0o070 {
|
||||
0o000 => gen16_case(ctx, DS, Offset16::Two(BX, SI), Imm16::None),
|
||||
0o001 => gen16_case(ctx, DS, Offset16::Two(BX, DI), Imm16::None),
|
||||
0o002 => gen16_case(ctx, SS, Offset16::Two(BP, SI), Imm16::None),
|
||||
0o003 => gen16_case(ctx, SS, Offset16::Two(BP, DI), Imm16::None),
|
||||
0o004 => gen16_case(ctx, DS, Offset16::One(SI), Imm16::None),
|
||||
0o005 => gen16_case(ctx, DS, Offset16::One(DI), Imm16::None),
|
||||
0o006 => gen16_case(ctx, DS, Offset16::Zero, Imm16::Imm16),
|
||||
0o007 => gen16_case(ctx, DS, Offset16::One(BX), Imm16::None),
|
||||
|
||||
0o100 => gen16_case(ctx, DS, Offset16::Two(BX, SI), Imm16::Imm8),
|
||||
0o101 => gen16_case(ctx, DS, Offset16::Two(BX, DI), Imm16::Imm8),
|
||||
0o102 => gen16_case(ctx, SS, Offset16::Two(BP, SI), Imm16::Imm8),
|
||||
0o103 => gen16_case(ctx, SS, Offset16::Two(BP, DI), Imm16::Imm8),
|
||||
0o104 => gen16_case(ctx, DS, Offset16::One(SI), Imm16::Imm8),
|
||||
0o105 => gen16_case(ctx, DS, Offset16::One(DI), Imm16::Imm8),
|
||||
0o106 => gen16_case(ctx, SS, Offset16::One(BP), Imm16::Imm8),
|
||||
0o107 => gen16_case(ctx, DS, Offset16::One(BX), Imm16::Imm8),
|
||||
|
||||
0o200 => gen16_case(ctx, DS, Offset16::Two(BX, SI), Imm16::Imm16),
|
||||
0o201 => gen16_case(ctx, DS, Offset16::Two(BX, DI), Imm16::Imm16),
|
||||
0o202 => gen16_case(ctx, SS, Offset16::Two(BP, SI), Imm16::Imm16),
|
||||
0o203 => gen16_case(ctx, SS, Offset16::Two(BP, DI), Imm16::Imm16),
|
||||
0o204 => gen16_case(ctx, DS, Offset16::One(SI), Imm16::Imm16),
|
||||
0o205 => gen16_case(ctx, DS, Offset16::One(DI), Imm16::Imm16),
|
||||
0o206 => gen16_case(ctx, SS, Offset16::One(BP), Imm16::Imm16),
|
||||
0o207 => gen16_case(ctx, DS, Offset16::One(BX), Imm16::Imm16),
|
||||
|
||||
_ => assert!(false),
|
||||
if modrm_byte.immediate != 0 || !have_something_on_stack {
|
||||
ctx.builder.const_i32(modrm_byte.immediate);
|
||||
if have_something_on_stack {
|
||||
ctx.builder.add_i32();
|
||||
}
|
||||
}
|
||||
|
||||
if modrm_byte.is_16 {
|
||||
ctx.builder.const_i32(0xFFFF);
|
||||
ctx.builder.and_i32();
|
||||
}
|
||||
jit_add_seg_offset(ctx, modrm_byte.segment);
|
||||
}
|
||||
|
||||
pub fn skip(ctx: &mut CpuContext, modrm_byte: u8) { let _ = decode(ctx, modrm_byte); }
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum Imm32 {
|
||||
None,
|
||||
|
@ -166,169 +239,6 @@ enum Imm32 {
|
|||
Imm32,
|
||||
}
|
||||
|
||||
enum Offset {
|
||||
Reg(u32),
|
||||
Sib,
|
||||
None,
|
||||
}
|
||||
|
||||
fn gen32_case(ctx: &mut JitContext, seg: u32, offset: Offset, imm: Imm32) {
|
||||
match offset {
|
||||
Offset::Sib => {
|
||||
let sib_byte = ctx.cpu.read_imm8();
|
||||
|
||||
gen_sib(ctx, sib_byte, imm == Imm32::None);
|
||||
|
||||
let immediate_value = match imm {
|
||||
Imm32::None => 0,
|
||||
Imm32::Imm8 => ctx.cpu.read_imm8s() as i32,
|
||||
Imm32::Imm32 => ctx.cpu.read_imm32() as i32,
|
||||
};
|
||||
|
||||
if immediate_value != 0 {
|
||||
ctx.builder.const_i32(immediate_value);
|
||||
ctx.builder.add_i32();
|
||||
}
|
||||
|
||||
{
|
||||
let m = sib_byte >> 3 & 7;
|
||||
|
||||
codegen::gen_profiler_stat_increment(
|
||||
ctx.builder,
|
||||
if m == 4 {
|
||||
if immediate_value == 0 {
|
||||
profiler::stat::MODRM_SIMPLE_REG
|
||||
}
|
||||
else {
|
||||
profiler::stat::MODRM_SIMPLE_REG_WITH_OFFSET
|
||||
}
|
||||
}
|
||||
else {
|
||||
profiler::stat::MODRM_COMPLEX
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
Offset::Reg(r) => {
|
||||
let immediate_value = match imm {
|
||||
Imm32::None => 0,
|
||||
Imm32::Imm8 => ctx.cpu.read_imm8s() as i32,
|
||||
Imm32::Imm32 => ctx.cpu.read_imm32() as i32,
|
||||
};
|
||||
codegen::gen_get_reg32(ctx, r);
|
||||
if immediate_value != 0 {
|
||||
ctx.builder.const_i32(immediate_value);
|
||||
ctx.builder.add_i32();
|
||||
}
|
||||
codegen::gen_profiler_stat_increment(
|
||||
ctx.builder,
|
||||
if immediate_value == 0 {
|
||||
profiler::stat::MODRM_SIMPLE_REG
|
||||
}
|
||||
else {
|
||||
profiler::stat::MODRM_SIMPLE_REG_WITH_OFFSET
|
||||
},
|
||||
);
|
||||
jit_add_seg_offset(ctx, seg);
|
||||
},
|
||||
Offset::None => {
|
||||
codegen::gen_profiler_stat_increment(
|
||||
ctx.builder,
|
||||
profiler::stat::MODRM_SIMPLE_CONST_OFFSET,
|
||||
);
|
||||
let immediate_value = match imm {
|
||||
Imm32::None => 0,
|
||||
Imm32::Imm8 => ctx.cpu.read_imm8s() as i32,
|
||||
Imm32::Imm32 => ctx.cpu.read_imm32() as i32,
|
||||
};
|
||||
ctx.builder.const_i32(immediate_value);
|
||||
jit_add_seg_offset(ctx, seg);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn gen32(ctx: &mut JitContext, modrm_byte: u8) {
|
||||
match modrm_byte & !0o070 {
|
||||
0o000 => gen32_case(ctx, DS, Offset::Reg(EAX), Imm32::None),
|
||||
0o001 => gen32_case(ctx, DS, Offset::Reg(ECX), Imm32::None),
|
||||
0o002 => gen32_case(ctx, DS, Offset::Reg(EDX), Imm32::None),
|
||||
0o003 => gen32_case(ctx, DS, Offset::Reg(EBX), Imm32::None),
|
||||
0o004 => gen32_case(ctx, DS, Offset::Sib, Imm32::None),
|
||||
0o005 => gen32_case(ctx, DS, Offset::None, Imm32::Imm32),
|
||||
0o006 => gen32_case(ctx, DS, Offset::Reg(ESI), Imm32::None),
|
||||
0o007 => gen32_case(ctx, DS, Offset::Reg(EDI), Imm32::None),
|
||||
|
||||
0o100 => gen32_case(ctx, DS, Offset::Reg(EAX), Imm32::Imm8),
|
||||
0o101 => gen32_case(ctx, DS, Offset::Reg(ECX), Imm32::Imm8),
|
||||
0o102 => gen32_case(ctx, DS, Offset::Reg(EDX), Imm32::Imm8),
|
||||
0o103 => gen32_case(ctx, DS, Offset::Reg(EBX), Imm32::Imm8),
|
||||
0o104 => gen32_case(ctx, DS, Offset::Sib, Imm32::Imm8),
|
||||
0o105 => gen32_case(ctx, SS, Offset::Reg(EBP), Imm32::Imm8),
|
||||
0o106 => gen32_case(ctx, DS, Offset::Reg(ESI), Imm32::Imm8),
|
||||
0o107 => gen32_case(ctx, DS, Offset::Reg(EDI), Imm32::Imm8),
|
||||
|
||||
0o200 => gen32_case(ctx, DS, Offset::Reg(EAX), Imm32::Imm32),
|
||||
0o201 => gen32_case(ctx, DS, Offset::Reg(ECX), Imm32::Imm32),
|
||||
0o202 => gen32_case(ctx, DS, Offset::Reg(EDX), Imm32::Imm32),
|
||||
0o203 => gen32_case(ctx, DS, Offset::Reg(EBX), Imm32::Imm32),
|
||||
0o204 => gen32_case(ctx, DS, Offset::Sib, Imm32::Imm32),
|
||||
0o205 => gen32_case(ctx, SS, Offset::Reg(EBP), Imm32::Imm32),
|
||||
0o206 => gen32_case(ctx, DS, Offset::Reg(ESI), Imm32::Imm32),
|
||||
0o207 => gen32_case(ctx, DS, Offset::Reg(EDI), Imm32::Imm32),
|
||||
|
||||
_ => assert!(false),
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_sib(ctx: &mut JitContext, sib_byte: u8, mod_is_zero: bool) {
|
||||
let r = sib_byte & 7;
|
||||
let m = sib_byte >> 3 & 7;
|
||||
|
||||
let seg;
|
||||
|
||||
// Generates: get_seg_prefix(seg) + base
|
||||
// Where base is a register or constant
|
||||
|
||||
if r == 4 {
|
||||
seg = SS;
|
||||
codegen::gen_get_reg32(ctx, ESP);
|
||||
}
|
||||
else if r == 5 {
|
||||
if mod_is_zero {
|
||||
seg = DS;
|
||||
let base = ctx.cpu.read_imm32();
|
||||
ctx.builder.const_i32(base as i32);
|
||||
}
|
||||
else {
|
||||
seg = SS;
|
||||
codegen::gen_get_reg32(ctx, EBP);
|
||||
}
|
||||
}
|
||||
else {
|
||||
seg = DS;
|
||||
codegen::gen_get_reg32(ctx, r as u32);
|
||||
}
|
||||
|
||||
jit_add_seg_offset(ctx, seg);
|
||||
|
||||
// We now have to generate an offset value to add
|
||||
|
||||
if m == 4 {
|
||||
// offset is 0, we don't need to add anything
|
||||
return;
|
||||
}
|
||||
|
||||
// Offset is reg32[m] << s, where s is:
|
||||
|
||||
let s = sib_byte >> 6 & 3;
|
||||
|
||||
codegen::gen_get_reg32(ctx, m as u32);
|
||||
ctx.builder.const_i32(s as i32);
|
||||
ctx.builder.shl_i32();
|
||||
|
||||
ctx.builder.add_i32();
|
||||
}
|
||||
|
||||
fn can_optimize_get_seg(ctx: &mut JitContext, segment: u32) -> bool {
|
||||
(segment == DS || segment == SS) && ctx.cpu.has_flat_segmentation()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue