Simplify generate_interpreter.js

This commit is contained in:
Fabian 2018-07-12 14:21:25 -06:00
parent bda133ba49
commit dac9b4591b

View file

@ -76,31 +76,17 @@ function gen_call(name, args)
return `${name}(${args.join(", ")});`;
}
function gen_modrm_mem_reg_split(name, modrm_resolve_prefix, mem_args, reg_args)
{
return {
type: "if-else",
if_blocks: [{
condition: "modrm_byte < 0xC0",
body: (modrm_resolve_prefix ? [modrm_resolve_prefix] : []).concat(gen_call(`${name}_mem`, mem_args)),
}],
else_block: {
body: [gen_call(`${name}_reg`, reg_args)],
},
};
}
/*
* Current naming scheme:
* instr(16|32|)_((66|F2|F3)?0F)?[0-9a-f]{2}(_[0-7])?(_mem|_reg|)
*/
function make_instruction_name(encoding, size, prefix_variant)
function make_instruction_name(encoding, size)
{
const suffix = encoding.os ? String(size) : "";
const opcode_hex = hex(encoding.opcode & 0xFF, 2);
const prefix_0f = (encoding.opcode & 0xFF00) === 0x0F00 ? "0F" : "";
const prefix = prefix_variant === undefined ? "" : hex(prefix_variant, 2);
const prefix = (encoding.opcode & 0xFF0000) === 0 ? "" : hex(encoding.opcode >> 16 & 0xFF, 2);
const fixed_g_suffix = encoding.fixed_g === undefined ? "" : `_${encoding.fixed_g}`;
return `instr${suffix}_${prefix}${prefix_0f}${opcode_hex}${fixed_g_suffix}`;
@ -110,26 +96,78 @@ function gen_instruction_body(encodings, size)
{
const encoding = encodings[0];
let has_66 = false;
let has_F2 = false;
let has_F3 = false;
let has_66 = [];
let has_F2 = [];
let has_F3 = [];
let no_prefix = [];
for(let e of encodings)
{
if((e.opcode >>> 16) === 0x66) has_66 = true;
if((e.opcode >>> 16) === 0xF2) has_F2 = true;
if((e.opcode >>> 16) === 0xF3) has_F3 = true;
if((e.opcode >>> 16) === 0x66) has_66.push(e);
else if((e.opcode >>> 16) === 0xF2) has_F2.push(e);
else if((e.opcode >>> 16) === 0xF3) has_F3.push(e);
else no_prefix.push(e);
}
if(has_66 || has_F2 || has_F3)
if(has_66.length || has_F2.length || has_F3.length)
{
console.assert((encoding.opcode & 0xFF00) === 0x0F00);
}
const instruction_postfix = encoding.block_boundary ? ["after_block_boundary();"] : [];
const code = [];
if(encoding.e)
{
code.push("int32_t modrm_byte = read_imm8();");
}
if(has_66.length || has_F2.length || has_F3.length)
{
const if_blocks = [];
if(has_66.length) {
const body = gen_instruction_body_after_prefix(has_66, size);
if_blocks.push({ condition: "prefixes_ & PREFIX_66", body, });
}
if(has_F2.length) {
const body = gen_instruction_body_after_prefix(has_F2, size);
if_blocks.push({ condition: "prefixes_ & PREFIX_F2", body, });
}
if(has_F3.length) {
const body = gen_instruction_body_after_prefix(has_F3, size);
if_blocks.push({ condition: "prefixes_ & PREFIX_F3", body, });
}
const else_block = {
body: gen_instruction_body_after_prefix(no_prefix, size),
};
return [].concat(
"int32_t prefixes_ = *prefixes;",
code,
{
type: "if-else",
if_blocks,
else_block,
}
);
}
else {
return [].concat(
code,
gen_instruction_body_after_prefix(encodings, size)
);
}
}
function gen_instruction_body_after_prefix(encodings, size)
{
const encoding = encodings[0];
if(encoding.fixed_g !== undefined)
{
console.assert(encoding.e);
// instruction with modrm byte where the middle 3 bits encode the instruction
// group by opcode without prefix plus middle bits of modrm byte
@ -141,77 +179,17 @@ function gen_instruction_body(encodings, size)
cases = Object.values(cases).sort((e1, e2) => e1.fixed_g - e2.fixed_g);
return [
"int32_t modrm_byte = read_imm8();",
{
type: "switch",
condition: "modrm_byte >> 3 & 7",
cases: cases.map(case_ => {
const fixed_g = case_.fixed_g;
const instruction_name = make_instruction_name(case_, size, undefined);
const instruction_postfix = case_.block_boundary ? ["after_block_boundary();"] : [];
const body = gen_instruction_body_after_fixed_g(case_, size);
let modrm_resolve_prefix = undefined;
if(case_.requires_prefix_call)
{
modrm_resolve_prefix = gen_call(instruction_name + "_mem_pre");
}
const mem_args = ["modrm_resolve(modrm_byte)"];
const reg_args = ["modrm_byte & 7"];
const imm_read = gen_read_imm_call(case_, size);
if(imm_read)
{
mem_args.push(imm_read);
reg_args.push(imm_read);
}
if(has_66 || has_F2 || has_F3)
{
const if_blocks = [];
if(has_66) {
const name = make_instruction_name(case_, size, 0x66);
const body = [gen_modrm_mem_reg_split(name, modrm_resolve_prefix, mem_args, reg_args)];
if_blocks.push({ condition: "prefixes_ & PREFIX_66", body, });
}
if(has_F2) {
const name = make_instruction_name(case_, size, 0xF2);
const body = [gen_modrm_mem_reg_split(name, modrm_resolve_prefix, mem_args, reg_args)];
if_blocks.push({ condition: "prefixes_ & PREFIX_F2", body, });
}
if(has_F3) {
const name = make_instruction_name(case_, size, 0xF3);
const body = [gen_modrm_mem_reg_split(name, modrm_resolve_prefix, mem_args, reg_args)];
if_blocks.push({ condition: "prefixes_ & PREFIX_F3", body, });
}
const else_block = {
body: [gen_modrm_mem_reg_split(instruction_name, modrm_resolve_prefix, mem_args, reg_args)],
};
return {
conditions: [fixed_g],
body: [
"int32_t prefixes_ = *prefixes;",
{
type: "if-else",
if_blocks,
else_block,
},
].concat(instruction_postfix),
};
}
else
{
const body = [gen_modrm_mem_reg_split(instruction_name, modrm_resolve_prefix, mem_args, reg_args)].concat(instruction_postfix);
return {
conditions: [fixed_g],
body,
};
}
return {
conditions: [fixed_g],
body,
};
}),
default_case: {
@ -220,66 +198,24 @@ function gen_instruction_body(encodings, size)
"trigger_ud();",
],
}
}
].concat(instruction_postfix);
},
];
}
else if(has_66 || has_F2 || has_F3)
{
// instruction without modrm byte but with prefix
console.assert(encoding.e);
console.assert(!encoding.ignore_mod);
console.assert(!encoding.requires_prefix_call, "Unexpected instruction (66/f2/f3 with prefix call)");
const imm_read = gen_read_imm_call(encoding, size);
const mem_args = ["modrm_resolve(modrm_byte)", "modrm_byte >> 3 & 7"];
const reg_args = ["modrm_byte & 7", "modrm_byte >> 3 & 7"];
if(imm_read)
{
mem_args.push(imm_read);
reg_args.push(imm_read);
}
const if_blocks = [];
const modrm_resolve_prefix = undefined;
if(has_66) {
const name = make_instruction_name(encoding, size, 0x66);
const body = [gen_modrm_mem_reg_split(name, modrm_resolve_prefix, mem_args, reg_args)];
if_blocks.push({ condition: "prefixes_ & PREFIX_66", body, });
}
if(has_F2) {
const name = make_instruction_name(encoding, size, 0xF2);
const body = [gen_modrm_mem_reg_split(name, modrm_resolve_prefix, mem_args, reg_args)];
if_blocks.push({ condition: "prefixes_ & PREFIX_F2", body, });
}
if(has_F3) {
const name = make_instruction_name(encoding, size, 0xF3);
const body = [gen_modrm_mem_reg_split(name, modrm_resolve_prefix, mem_args, reg_args)];
if_blocks.push({ condition: "prefixes_ & PREFIX_F3", body, });
}
const else_block = {
body: [gen_modrm_mem_reg_split(make_instruction_name(encoding, size), modrm_resolve_prefix, mem_args, reg_args)],
};
return [
"int32_t modrm_byte = read_imm8();",
"int32_t prefixes_ = *prefixes;",
{
type: "if-else",
if_blocks,
else_block,
}
].concat(instruction_postfix);
}
else if(encoding.fixed_g === undefined && encoding.e)
{
// instruction with modrm byte where the middle 3 bits encode a register
else {
console.assert(encodings.length === 1);
return gen_instruction_body_after_fixed_g(encodings[0], size);
}
}
function gen_instruction_body_after_fixed_g(encoding, size)
{
const instruction_postfix = encoding.block_boundary ? ["after_block_boundary();"] : [];
const imm_read = gen_read_imm_call(encoding, size);
const instruction_name = make_instruction_name(encoding, size);
if(encoding.e)
{
// instruction with modrm byte
const instruction_name = make_instruction_name(encoding, size);
@ -300,15 +236,21 @@ function gen_instruction_body(encodings, size)
// Has modrm byte, but the 2 mod bits are ignored and both
// operands are always registers (0f20-0f24)
return [
"int32_t modrm_byte = read_imm8();",
return [].concat(
gen_call(instruction_name, ["modrm_byte & 7", "modrm_byte >> 3 & 7"]),
].concat(instruction_postfix);
instruction_postfix
);
}
else
{
const mem_args = ["modrm_resolve(modrm_byte)", "modrm_byte >> 3 & 7"];
const reg_args = ["modrm_byte & 7", "modrm_byte >> 3 & 7"];
const mem_args = ["modrm_resolve(modrm_byte)"];
const reg_args = ["modrm_byte & 7"];
if(encoding.fixed_g === undefined)
{
mem_args.push("modrm_byte >> 3 & 7");
reg_args.push("modrm_byte >> 3 & 7");
}
if(imm_read)
{
@ -316,19 +258,28 @@ function gen_instruction_body(encodings, size)
reg_args.push(imm_read);
}
return [
"int32_t modrm_byte = read_imm8();",
gen_modrm_mem_reg_split(instruction_name, modrm_resolve_prefix, mem_args, reg_args),
].concat(instruction_postfix);
return [].concat(
{
type: "if-else",
if_blocks: [
{
condition: "modrm_byte < 0xC0",
body: [].concat(
modrm_resolve_prefix ? [modrm_resolve_prefix] : [],
gen_call(`${instruction_name}_mem`, mem_args)
),
}
],
else_block: {
body: [gen_call(`${instruction_name}_reg`, reg_args)],
},
},
instruction_postfix
);
}
}
else
{
// instruction without modrm byte or prefix
const imm_read = gen_read_imm_call(encoding, size);
const instruction_name = make_instruction_name(encoding, size);
const args = [];
if(imm_read)
@ -347,7 +298,10 @@ function gen_instruction_body(encodings, size)
args.push("read_imm8()");
}
return [gen_call(instruction_name, args)].concat(instruction_postfix);
return [].concat(
gen_call(instruction_name, args),
instruction_postfix
);
}
}