Refactor modrm decoding for jit

This commit is contained in:
Fabian 2020-12-31 19:14:31 -06:00
parent 9ccef87b88
commit ab46fe4f37
5 changed files with 441 additions and 518 deletions

View file

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

View file

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

View file

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

View file

@ -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()
}