improve segment prefix handling and custom code generation for lea

This commit is contained in:
Awal Garg 2018-03-08 23:47:34 +05:30 committed by Fabian
parent 43288ecdbd
commit 54a43ab437
10 changed files with 134 additions and 66 deletions

View file

@ -99,6 +99,11 @@ function gen_codegen_call_modrm(name, args)
].join(" ");
}
function gen_custom_jit_call(name, args)
{
return gen_call(`${name}_jit`, args);
}
function gen_modrm_mem_reg_split(name, gen_call_fns, mem_prefix_call, mem_args, reg_args, postfixes={})
{
const { mem_call_fn, reg_call_fn } = gen_call_fns;
@ -399,6 +404,23 @@ function gen_instruction_body(encodings, size)
gen_codegen_call(instruction_name, ["modrm_byte & 7", "modrm_byte >> 3 & 7"]),
].concat(instruction_postfix);
}
else if(encoding.opcode === 0x8D) // lea
{
const mem_args = ["modrm_byte"];
const reg_args = ["0", "0"];
gen_call_fns.mem_call_fn = gen_custom_jit_call;
return [
"int32_t modrm_byte = read_imm8();",
gen_modrm_mem_reg_split(
instruction_name,
gen_call_fns,
undefined,
mem_args,
reg_args,
get_nonfaulting_mem_reg_postfix(encoding)
),
].concat(instruction_postfix);
}
else
{
let modrm_resolve_prefix = undefined;

View file

@ -96,7 +96,7 @@ const encodings = [
{ opcode: 0x8B, nonfaulting: 1, os: 1, e: 1, },
{ opcode: 0x8C, os: 1, e: 1, skip: 1, },
{ opcode: 0x8D, nonfaulting: 1, os: 1, e: 1, only_mem: 1, requires_prefix_call: 1, }, // lea
{ opcode: 0x8D, nonfaulting: 1, os: 1, e: 1, only_mem: 1, requires_prefix_call: 1, custom: 1, }, // lea
{ opcode: 0x8E, e: 1, skip: 1, },
{ opcode: 0x8F, os: 1, e: 1, fixed_g: 0, requires_prefix_call: 1, }, // pop r/m

View file

@ -3,6 +3,7 @@
#include <stdlib.h>
#include "../const.h"
#include "../cpu.h"
#include "../global_pointers.h"
#include "codegen.h"
#include "cstring.h"
@ -13,22 +14,17 @@
static Buffer op = { .start = codegen_buffer_op, .ptr = codegen_buffer_op, .len = 0x1000 };
static Buffer cs = { .start = codegen_buffer_cs, .ptr = codegen_buffer_cs, .len = 0x1000 };
static Buffer instruction_body = {
Buffer instruction_body = {
.start = codegen_buffer_instruction_body,
.ptr = codegen_buffer_instruction_body,
.len = 0x1000,
};
extern bool is_asize_32(void);
extern int32_t read_imm8();
extern int32_t read_imm8s();
extern int32_t read_imm16();
extern int32_t read_imm32s();
static uint8_t* op_ptr_reset_location;
static uint32_t import_table_size_reset_value;
static uint32_t initial_import_count;
static void jit_get_seg_prefix(int32_t default_segment);
static void jit_resolve_modrm32_(int32_t modrm_byte);
static void jit_resolve_modrm16_(int32_t modrm_byte);
@ -44,20 +40,9 @@ void gen_init()
write_import_section_preamble();
// add initial imports
uint8_t _fn_get_seg_prefix_ds_idx = write_import_entry(
"get_seg_prefix_ds", 17, FN1_RET_TYPE_INDEX);
assert(_fn_get_seg_prefix_ds_idx == fn_get_seg_prefix_ds_idx);
UNUSED(_fn_get_seg_prefix_ds_idx);
uint8_t _fn_get_seg_prefix_ss_idx = write_import_entry(
"get_seg_prefix_ss", 17, FN1_RET_TYPE_INDEX);
assert(_fn_get_seg_prefix_ss_idx == fn_get_seg_prefix_ss_idx);
UNUSED(_fn_get_seg_prefix_ss_idx);
uint8_t _fn_get_seg_prefix_idx = write_import_entry(
"get_seg_prefix", 14, FN1_RET_TYPE_INDEX);
assert(_fn_get_seg_prefix_idx == fn_get_seg_prefix_idx);
UNUSED(_fn_get_seg_prefix_idx);
uint8_t _fn_get_seg_idx = write_import_entry("get_seg", 7, FN1_RET_TYPE_INDEX);
assert(_fn_get_seg_idx == fn_get_seg_idx);
UNUSED(_fn_get_seg_idx);
// store state of current pointers etc. so we can reset them later
op_ptr_reset_location = op.ptr;
@ -297,7 +282,7 @@ void gen_block_end()
MODRM_ENTRY(0x40 | (row), gen_modrm_entry_1(seg, reg, read_imm8s()))\
MODRM_ENTRY(0x80 | (row), gen_modrm_entry_1(seg, reg, read_imm16()))
static void inline gen_modrm_entry_0(int32_t fn_idx, int32_t reg16_idx_1, int32_t reg16_idx_2, int32_t imm)
static void inline gen_modrm_entry_0(int32_t segment, int32_t reg16_idx_1, int32_t reg16_idx_2, int32_t imm)
{
// generates: fn( ( reg1 + reg2 + imm ) & 0xFFFF )
load_aligned_u16(&instruction_body, reg16_idx_1);
@ -310,10 +295,11 @@ static void inline gen_modrm_entry_0(int32_t fn_idx, int32_t reg16_idx_1, int32_
push_i32(&instruction_body, 0xFFFF);
and_i32(&instruction_body);
call_fn(&instruction_body, fn_idx);
jit_get_seg_prefix(segment);
add_i32(&instruction_body);
}
static void gen_modrm_entry_1(int32_t fn_idx, int32_t reg16_idx, int32_t imm)
static void gen_modrm_entry_1(int32_t segment, int32_t reg16_idx, int32_t imm)
{
// generates: fn ( ( reg + imm ) & 0xFFFF )
load_aligned_u16(&instruction_body, reg16_idx);
@ -323,31 +309,61 @@ static void gen_modrm_entry_1(int32_t fn_idx, int32_t reg16_idx, int32_t imm)
push_i32(&instruction_body, 0xFFFF);
and_i32(&instruction_body);
call_fn(&instruction_body, fn_idx);
jit_get_seg_prefix(segment);
add_i32(&instruction_body);
}
static void jit_get_seg_prefix(int32_t default_segment)
{
int32_t prefix = *prefixes & PREFIX_MASK_SEGMENT;
if(prefix)
{
if(prefix == SEG_PREFIX_ZERO)
{
// TODO: Remove this special case
push_i32(&instruction_body, 0);
}
else
{
push_i32(&instruction_body, prefix - 1);
call_fn(&instruction_body, fn_get_seg_idx);
}
}
else
{
write_raw_u8(&instruction_body, OP_I32CONST);
write_raw_u8(&instruction_body, default_segment);
call_fn(&instruction_body, fn_get_seg_idx);
}
}
static void gen_modrm_entry_2()
{
push_i32(&instruction_body, read_imm16());
jit_get_seg_prefix(DS);
add_i32(&instruction_body);
}
static void jit_resolve_modrm16_(int32_t modrm_byte)
{
int32_t const ds = fn_get_seg_prefix_ds_idx;
int32_t const ss = fn_get_seg_prefix_ss_idx;
switch(modrm_byte)
{
// The following casts cause some weird issue with emscripten and cause
// a performance hit. XXX: look into this later.
MODRM_ENTRY16_0(0, ds, (int32_t)(reg16 + BX), (int32_t)(reg16 + SI))
MODRM_ENTRY16_0(1, ds, (int32_t)(reg16 + BX), (int32_t)(reg16 + DI))
MODRM_ENTRY16_0(2, ss, (int32_t)(reg16 + BP), (int32_t)(reg16 + SI))
MODRM_ENTRY16_0(3, ss, (int32_t)(reg16 + BP), (int32_t)(reg16 + DI))
MODRM_ENTRY16_1(4, ds, (int32_t)(reg16 + SI))
MODRM_ENTRY16_1(5, ds, (int32_t)(reg16 + DI))
MODRM_ENTRY16_0(0, DS, (int32_t)(reg16 + BX), (int32_t)(reg16 + SI))
MODRM_ENTRY16_0(1, DS, (int32_t)(reg16 + BX), (int32_t)(reg16 + DI))
MODRM_ENTRY16_0(2, SS, (int32_t)(reg16 + BP), (int32_t)(reg16 + SI))
MODRM_ENTRY16_0(3, SS, (int32_t)(reg16 + BP), (int32_t)(reg16 + DI))
MODRM_ENTRY16_1(4, DS, (int32_t)(reg16 + SI))
MODRM_ENTRY16_1(5, DS, (int32_t)(reg16 + DI))
// special case
MODRM_ENTRY(0x00 | 6, call_fn_with_arg(&instruction_body, ds, read_imm16()))
MODRM_ENTRY(0x40 | 6, gen_modrm_entry_1(ss, (int32_t)(reg16 + BP), read_imm8s()))
MODRM_ENTRY(0x80 | 6, gen_modrm_entry_1(ss, (int32_t)(reg16 + BP), read_imm16()))
MODRM_ENTRY(0x00 | 6, gen_modrm_entry_2())
MODRM_ENTRY(0x40 | 6, gen_modrm_entry_1(SS, (int32_t)(reg16 + BP), read_imm8s()))
MODRM_ENTRY(0x80 | 6, gen_modrm_entry_1(SS, (int32_t)(reg16 + BP), read_imm16()))
MODRM_ENTRY16_1(7, ds, (int32_t)(reg16 + BX))
MODRM_ENTRY16_1(7, DS, (int32_t)(reg16 + BX))
default:
assert(false);
@ -359,14 +375,15 @@ static void jit_resolve_modrm16_(int32_t modrm_byte)
MODRM_ENTRY(0x40 | (row), gen_modrm32_entry(seg, reg, read_imm8s()))\
MODRM_ENTRY(0x80 | (row), gen_modrm32_entry(seg, reg, read_imm32s()))
static void gen_modrm32_entry(int32_t fn_idx, int32_t reg32s_idx, int32_t imm)
static void gen_modrm32_entry(int32_t segment, int32_t reg32s_idx, int32_t imm)
{
// generates: fn ( reg + imm )
load_aligned_i32(&instruction_body, reg32s_idx);
push_i32(&instruction_body, imm);
add_i32(&instruction_body);
call_fn(&instruction_body, fn_idx);
jit_get_seg_prefix(segment);
add_i32(&instruction_body);
}
static void jit_resolve_sib(bool mod)
@ -408,11 +425,7 @@ static void jit_resolve_sib(bool mod)
// generate: get_seg_prefix(seg) + base
// Where base is accessed from memory if base_is_mem_access or written as a constant otherwise
dbg_assert(seg < 16);
write_raw_u8(&instruction_body, OP_I32CONST);
write_raw_u8(&instruction_body, seg);
call_fn(&instruction_body, fn_get_seg_prefix_idx);
jit_get_seg_prefix(seg);
if(base_is_mem_access)
{
@ -460,28 +473,32 @@ static void modrm32_special_case_2()
add_i32(&instruction_body);
}
static void gen_modrm32_entry_1()
{
push_i32(&instruction_body, read_imm32s());
jit_get_seg_prefix(DS);
add_i32(&instruction_body);
}
static void jit_resolve_modrm32_(int32_t modrm_byte)
{
int32_t const ds = fn_get_seg_prefix_ds_idx;
int32_t const ss = fn_get_seg_prefix_ss_idx;
switch(modrm_byte)
{
MODRM_ENTRY32_0(0, ds, (int32_t)(reg32s + EAX))
MODRM_ENTRY32_0(1, ds, (int32_t)(reg32s + ECX))
MODRM_ENTRY32_0(2, ds, (int32_t)(reg32s + EDX))
MODRM_ENTRY32_0(3, ds, (int32_t)(reg32s + EBX))
MODRM_ENTRY32_0(0, DS, (int32_t)(reg32s + EAX))
MODRM_ENTRY32_0(1, DS, (int32_t)(reg32s + ECX))
MODRM_ENTRY32_0(2, DS, (int32_t)(reg32s + EDX))
MODRM_ENTRY32_0(3, DS, (int32_t)(reg32s + EBX))
// special cases
MODRM_ENTRY(0x00 | 4, jit_resolve_sib(false))
MODRM_ENTRY(0x40 | 4, modrm32_special_case_1())
MODRM_ENTRY(0x80 | 4, modrm32_special_case_2())
MODRM_ENTRY(0x00 | 5, call_fn_with_arg(&instruction_body, ds, read_imm32s()))
MODRM_ENTRY(0x40 | 5, gen_modrm32_entry(ss, (int32_t)(reg32s + EBP), read_imm8s()))
MODRM_ENTRY(0x80 | 5, gen_modrm32_entry(ss, (int32_t)(reg32s + EBP), read_imm32s()))
MODRM_ENTRY(0x00 | 5, gen_modrm32_entry_1())
MODRM_ENTRY(0x40 | 5, gen_modrm32_entry(SS, (int32_t)(reg32s + EBP), read_imm8s()))
MODRM_ENTRY(0x80 | 5, gen_modrm32_entry(SS, (int32_t)(reg32s + EBP), read_imm32s()))
MODRM_ENTRY32_0(6, ds, (int32_t)(reg32s + ESI))
MODRM_ENTRY32_0(7, ds, (int32_t)(reg32s + EDI))
MODRM_ENTRY32_0(6, DS, (int32_t)(reg32s + ESI))
MODRM_ENTRY32_0(7, DS, (int32_t)(reg32s + EDI))
default:
assert(false);

View file

@ -2,6 +2,8 @@
#include <stdint.h>
#include "util.h"
#define FN0_TYPE_INDEX 0
#define FN1_TYPE_INDEX 1
#define FN2_TYPE_INDEX 2
@ -13,9 +15,9 @@
#define NR_FN_TYPE_INDEXES 7
static uint8_t const fn_get_seg_prefix_ds_idx = 0;
static uint8_t const fn_get_seg_prefix_ss_idx = 1;
static uint8_t const fn_get_seg_prefix_idx = 2;
extern Buffer instruction_body;
static uint8_t const fn_get_seg_idx = 0;
void gen_init(void);
void gen_reset(void);

View file

@ -64,14 +64,14 @@ static void write_leb_u32(Buffer* buf, uint32_t v)
} while (v != 0);
}
extern void inline write_fixed_leb16_to_ptr(uint8_t* ptr, uint16_t x)
static void inline write_fixed_leb16_to_ptr(uint8_t* ptr, uint16_t x)
{
dbg_assert(x < (1 << 14)); // we have 14 bits of available space in 2 bytes for leb
*ptr = (x & 0b1111111) | 0b10000000;
*(ptr + 1) = x >> 7;
}
void append_buffer(Buffer *dest, Buffer *src)
static void append_buffer(Buffer *dest, Buffer *src)
{
assert(dest->len - (dest->ptr - dest->start) >= (src->ptr - src->start));

View file

@ -1014,9 +1014,11 @@ void segment_prefix_op(int32_t seg)
jit_instr_flags segment_prefix_op_jit(int32_t seg)
{
assert(seg <= 5);
*prefixes |= seg + 1;
gen_add_prefix_bits(seg + 1);
jit_instr_flags instr_flags = jit_prefix_instruction();
gen_clear_prefixes();
*prefixes = 0;
return instr_flags;
}

View file

@ -5,6 +5,7 @@
#include "arith.h"
#include "codegen/codegen.h"
#include "codegen/wasm_util.h"
#include "const.h"
#include "cpu.h"
#include "fpu.h"
@ -527,6 +528,28 @@ void instr32_8D_mem(int32_t addr, int32_t r) {
*prefixes = 0;
}
void instr16_8D_mem_jit(int32_t modrm_byte)
{
int32_t loc = (int32_t) &reg16[get_reg16_index(modrm_byte >> 3 & 7)];
push_u32(&instruction_body, loc);
// override prefix, so modrm_resolve does not return the segment part
*prefixes |= SEG_PREFIX_ZERO;
gen_modrm_resolve(modrm_byte);
store_aligned_u16(&instruction_body);
*prefixes = 0;
}
void instr32_8D_mem_jit(int32_t modrm_byte)
{
int32_t loc = (int32_t) &reg32s[modrm_byte >> 3 & 7];
push_u32(&instruction_body, loc);
// override prefix, so modrm_resolve does not return the segment part
*prefixes |= SEG_PREFIX_ZERO;
gen_modrm_resolve(modrm_byte);
store_aligned_i32(&instruction_body);
*prefixes = 0;
}
void instr_8E_helper(int32_t data, int32_t mod)
{
if(mod == ES || mod == SS || mod == DS || mod == FS || mod == GS)

View file

@ -512,6 +512,8 @@ void instr16_8D_mem(int32_t addr, int32_t r);
void instr32_8D_reg(int32_t r, int32_t r2);
void instr32_8D_mem_pre(void);
void instr32_8D_mem(int32_t addr, int32_t r);
void instr16_8D_jit(void);
void instr32_8D_jit(void);
void instr_8E_helper(int32_t data, int32_t mod);
void instr_8E_mem(int32_t addr, int32_t r);
void instr_8E_reg(int32_t r1, int32_t r);

View file

@ -1,3 +1,5 @@
#pragma once
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>

View file

@ -111,9 +111,7 @@ function test(gen)
fn2(arg0, arg1) { store.push(["fn2", arg0, arg1]); },
fn1r(arg0) { store.push(["fn1r", arg0]); },
fn2r(arg0, arg1) { store.push(["fn2r", arg0, arg1]); },
get_seg_prefix_ds() {},
get_seg_prefix_ss() {},
get_seg_prefix() {},
get_seg() {},
m: new WebAssembly.Memory({ initial: memory_size / 64 / 1024 }),
},
};