last thing on runtime encode of the night

This commit is contained in:
ed
2026-09-09 22:35:45 -04:00
parent be55514e93
commit 4264e19b37
+225 -17
View File
@@ -1,5 +1,6 @@
#ifdef INTELLISENSE_DIRECTIVES #ifdef INTELLISENSE_DIRECTIVES
# include "encode.h" # include "encode.h"
# include "encoder_table.h"
#endif #endif
internal void internal void
@@ -12,40 +13,247 @@ x8616_encode_push(FArena_R arena, X8616_InfoList_R msgs, X8616_EncodeStatus stat
x8616_info_push(arena, msgs, kind, code, id, size, expected, actual); x8616_info_push(arena, msgs, kind, code, id, size, expected, actual);
} }
FI_ void x8616_encode_buf_u1(U1* buf, U1_R n, U1 value) { buf[n[0]] = value; n[0] += 1; } FI_ void x8616_encode_buf_u1(U1_R buf, U1_R n, U1 value) { buf[n[0]] = value; n[0] += 1; }
FI_ void x8616_encode_buf_u2(U1* buf, U1_R n, U2 value) { FI_ void x8616_encode_buf_u2(U1_R buf, U1_R n, U2 value) {
x8616_encode_buf_u1(buf, n, u1_(value)); x8616_encode_buf_u1(buf, n, u1_(value));
x8616_encode_buf_u1(buf, n, u1_(value >> 8)); x8616_encode_buf_u1(buf, n, u1_(value >> 8));
} }
FI_ void x8616_encode_buf_disp(U1* buf, U1_R n, S2 value, U1 bytes) { FI_ void x8616_encode_buf_disp(U1_R buf, U1_R n, S2 value, U1 bytes) {
if (bytes == 1) x8616_encode_buf_u1(buf, n, u1_(value)); if (bytes == 1) x8616_encode_buf_u1(buf, n, u1_(value));
if (bytes == 2) x8616_encode_buf_u2(buf, n, u2_(value)); if (bytes == 2) x8616_encode_buf_u2(buf, n, u2_(value));
} }
I_ B4 x8616_encode_is_alu (X8616_Op op) { return op >= x8616_op_add && op <= x8616_op_cmp; }
I_ B4 x8616_encode_is_shift (X8616_Op op) { return op >= x8616_op_shl && op <= x8616_op_rcr; }
I_ B4 x8616_encode_is_jcc (X8616_Op op) { return op >= x8616_op_je && op <= x8616_op_jns; }
I_ U1 x8616_encode_alu_from_op(X8616_Op op) { return u1_(op - x8616_op_add); }
I_ U1 x8616_encode_cc_from_op (X8616_Op op) {
for (U1 i = 0; i < Array_len(x8616_op_from_cc); ++i) if (x8616_op_from_cc[i] == op) return i;
return 0;
}
I_ U1 x8616_encode_shift_from_op(X8616_Op op) {
for (U1 i = 0; i < Array_len(x8616_op_from_shift); ++i) if (x8616_op_from_shift[i] == op) return i;
return 0;
}
I_ void x8616_encode_or_field(U1_R header, X8616_BitField f, U1 value) {
header[0] |= (value << f.shift) & x8616_field_mask(f.shift, f.width);
}
FI_ U1 x8616_encode_prefix_count(X8616_DecodedInstruction_R inst) {
return u1_(inst->prefixes.lock) + u1_(inst->prefixes.has_repeat) + u1_(inst->prefixes.has_segment);
}
FI_ B4 x8616_encode_is_acc(X8616_DecodedOperand_R op) {
if ((op->flags & x8616_decoded_operand_register) == 0) return 0;
if (op->width == x8616_width_byte) return op->reg.r8 == x8616_al;
return op->reg.r16 == x8616_ax;
}
RO_ global U2 x8616_encode_slot_any[] = {
[x8616_operand_none] = 0,
[x8616_operand_rm] = x8616_decoded_operand_register | x8616_decoded_operand_memory,
[x8616_operand_reg_modrm] = x8616_decoded_operand_register,
[x8616_operand_reg_opcode] = x8616_decoded_operand_register,
[x8616_operand_segment_modrm] = x8616_decoded_operand_segment,
[x8616_operand_segment_opcode] = x8616_decoded_operand_segment,
[x8616_operand_acc] = x8616_decoded_operand_register,
[x8616_operand_imm] = x8616_decoded_operand_immediate,
[x8616_operand_imm8] = x8616_decoded_operand_immediate,
[x8616_operand_imm16] = x8616_decoded_operand_immediate,
[x8616_operand_mem_direct] = x8616_decoded_operand_memory,
[x8616_operand_rel8] = x8616_decoded_operand_relative,
[x8616_operand_rel16] = x8616_decoded_operand_relative,
[x8616_operand_far_ptr] = x8616_decoded_operand_far_ptr,
[x8616_operand_dx] = x8616_decoded_operand_register,
[x8616_operand_shift_count] = x8616_decoded_operand_register | x8616_decoded_operand_immediate,
};
I_ B4 x8616_encode_slot_match(X8616_Operand slot, X8616_DecodedOperand_R op, X8616_DecodedInstruction_R inst) {
B4 ok = (op->flags & x8616_encode_slot_any[slot]) != 0;
ok &= (slot != x8616_operand_acc) || x8616_encode_is_acc(op);
ok &= (slot != x8616_operand_dx) || (op->reg.r16 == x8616_dx);
ok &= (slot != x8616_operand_imm8) || (op->immediate <= 0xFF);
ok &= (slot != x8616_operand_mem_direct) || ((op->flags & x8616_decoded_operand_direct) != 0);
ok &= (slot != x8616_operand_shift_count) || ((op->flags & x8616_decoded_operand_register) && op->reg.r8 == x8616_cl) || (op->immediate == 1);
if (slot == x8616_operand_rel8 && ok) {
S2 machine = s2_(op->displacement - s2_(x8616_encode_prefix_count(inst) + 2));
ok = machine >= -128 && machine <= 127;
}
return ok;
}
FI_ U1 x8616_encode_enc_count(X8616_Encoding_R enc) { return u1_(enc->operands[0] != x8616_operand_none) + u1_(enc->operands[1] != x8616_operand_none); }
I_ B4 x8616_encode_op_match(X8616_Encoding_R enc, X8616_Op op) {
B4 prefix = (enc->flags & x8616_encoding_prefix) != 0;
B4 exact = enc->op == op;
B4 family = enc->op == x8616_op_invalid;
B4 alu = family && (enc->fields.alu.width || enc->digit_kind == x8616_digit_alu) && x8616_encode_is_alu(op);
B4 cc = family && enc->fields.cc.width && x8616_encode_is_jcc(op);
B4 shift = family && enc->digit_kind == x8616_digit_shift && x8616_encode_is_shift(op);
return prefix == 0 && (exact || alu || cc || shift);
}
I_ B4 x8616_encode_row_match(X8616_Encoding_R enc, X8616_DecodedInstruction_R inst, U1 d) {
B4 op_ok = x8616_encode_op_match(enc, inst->op);
B4 enc_far = (enc->flags & x8616_encoding_far) != 0;
B4 inst_far = (inst->flags & x8616_encoding_far) != 0;
inst_far |= (inst->operands[0].flags & x8616_decoded_operand_far_ptr) != 0;
inst_far |= (inst->operands[1].flags & x8616_decoded_operand_far_ptr) != 0;
B4 far_ok = enc_far == inst_far;
B4 width_any = enc->width == x8616_width_dynamic || inst->width == x8616_width_dynamic;
B4 width_ok = width_any || enc->width == inst->width;
B4 count_ok = x8616_encode_enc_count(enc) == inst->operand_count;
B4 d_ok = enc->fields.d.width || d == 0;
B4 slots_ok = 1;
for (U1 i = 0; i < inst->operand_count; ++i) {
U1 slot_i = d ? (i ^ 1) : i;
slots_ok &= x8616_encode_slot_match(enc->operands[slot_i], inst->operands + i, inst);
}
return op_ok && far_ok && width_ok && count_ok && d_ok && slots_ok;
}
FI_ U1 x8616_encode_row_score(X8616_Encoding const* enc) {
U1 score = 0;
for (U1 i = 0; i < 2; ++i) {
X8616_Operand s = enc->operands[i];
if (s == x8616_operand_reg_opcode || s == x8616_operand_acc || s == x8616_operand_mem_direct) score += 2;
if (s == x8616_operand_rel8 || s == x8616_operand_imm8) score += 1;
}
return score;
}
I_ B4 x8616_encode_slot_modrm(X8616_Operand s) { return s == x8616_operand_rm || s == x8616_operand_reg_modrm || s == x8616_operand_segment_modrm; }
I_ B4 x8616_encode_needs_modrm(X8616_Encoding const* enc) {
B4 masked = enc->mod_rm.mask != 0;
B4 digit = enc->digit_kind != x8616_digit_none;
B4 slots = x8616_encode_slot_modrm(enc->operands[0]) || x8616_encode_slot_modrm(enc->operands[1]);
return masked || digit || slots;
}
internal B4
x8616_encode_assemble(X8616_DecodedInstruction_R inst)
{
X8616_Encoding const* best = 0;
U1 best_d = 0;
U1 best_score = 0;
B4 found = 0;
for (U4 id = 0; id < Array_len(x8616_encodings); ++id)
{
X8616_Encoding_R enc = x8616_encodings + id;
U1 d_hi = enc->fields.d.width ? 1 : 0;
for (U1 d = 0; d <= d_hi; ++d) {
if (x8616_encode_row_match(enc, inst, d) == 0) continue;
U1 score = x8616_encode_row_score(enc);
B4 not_bested = found && (score < best_score || (score == best_score && d < best_d));
if (not_bested) continue;
best = enc; best_d = d; best_score = score; found = 1;
}
}
if (found == 0) return 0;
X8616_DecodedOperand_R slot[X8616_OPERAND_SOURCE_COUNT] = {0};
for (U1 op_id = 0; op_id < inst->operand_count; ++op_id) {
U1 slot_id = best_d ? (op_id ^ 1) : op_id;
slot[best->operands[slot_id]] = inst->operands + op_id;
}
X8616_DecodedOperand_R operand_acc = slot[x8616_operand_acc];
X8616_Width w = inst->width == x8616_width_word ? x8616_w_word : x8616_w_byte;
if (operand_acc) w = operand_acc->width == x8616_width_word ? x8616_w_word : x8616_w_byte;
U1 header = best->header.bits;
X8616_DecodedOperand_R sc = slot[x8616_operand_shift_count];
X8616_DecodedOperand_R imm = slot[x8616_operand_imm];
if (imm == 0) imm = slot[x8616_operand_imm8];
if (imm == 0) imm = slot[x8616_operand_imm16];
U1 s = 0;
if (best->fields.s.width && imm) {
s = (inst->width == x8616_width_word && imm->immediate_bytes <= 1) || (imm->flags & x8616_decoded_operand_sign_extended);
}
U1 v = sc && (sc->flags & x8616_decoded_operand_register);
U1 reg_op = slot[x8616_operand_reg_opcode] ? u1_(slot[x8616_operand_reg_opcode ]->reg.r16) : 0;
U1 sr_op = slot[x8616_operand_segment_opcode] ? u1_(slot[x8616_operand_segment_opcode]->segment) : 0;
x8616_encode_or_field(& header, best->fields.w, u1_(w));
x8616_encode_or_field(& header, best->fields.d, best_d);
x8616_encode_or_field(& header, best->fields.alu, x8616_encode_alu_from_op(inst->op));
x8616_encode_or_field(& header, best->fields.cc, x8616_encode_cc_from_op(inst->op));
x8616_encode_or_field(& header, best->fields.reg, reg_op);
x8616_encode_or_field(& header, best->fields.sr, sr_op);
x8616_encode_or_field(& header, best->fields.v, v);
x8616_encode_or_field(& header, best->fields.s, s);
header = (header & ~best->header.mask) | (best->header.bits & best->header.mask);
if (sc && (sc->flags & x8616_decoded_operand_immediate) && sc->immediate == 1) sc->immediate_bytes = 0;
U1 modrm = 0;
B4 has_modrm = x8616_encode_needs_modrm(best);
X8616_DecodedOperand_R rm_op = slot[x8616_operand_rm];
U1 mod = x8616_mod_reg;
U1 rm = 0;
if (rm_op) {
B4 mem = (rm_op->flags & x8616_decoded_operand_memory) != 0;
B4 dir = (rm_op->flags & x8616_decoded_operand_direct) != 0;
B4 bp0 = mem && dir == 0 && rm_op->displacement_bytes == 0 && rm_op->ea == x8616_ea_bp;
if (bp0) { rm_op->displacement_bytes = 1; rm_op->displacement = 0; }
U1 db = rm_op->displacement_bytes;
mod = mem ? (dir ? x8616_mod_mem : (db > 2 ? 2 : db)) : x8616_mod_reg;
rm = dir ? u1_(x8616_ea_direct) : (mem ? u1_(rm_op->ea) : u1_(rm_op->reg.r16));
}
U1 kind_digit[3] = { 0, x8616_encode_alu_from_op(inst->op), x8616_encode_shift_from_op(inst->op) };
U1 reg = slot[x8616_operand_reg_modrm] ? u1_(slot[x8616_operand_reg_modrm]->reg.r16) : 0;
if (best->digit_kind) reg = kind_digit[best->digit_kind];
X8616_DecodedOperand_R sr_m = slot[x8616_operand_segment_modrm];
modrm = sr_m ? x8616_enc_modrm_seg(mod, sr_m->segment, rm) : x8616_enc_modrm(mod, reg, rm);
modrm = (modrm & ~best->mod_rm.mask) | (best->mod_rm.bits & best->mod_rm.mask);
X8616_DecodedOperand_R rel = slot[x8616_operand_rel8];
U1 rel_bytes = 1;
if (rel == 0) { rel = slot[x8616_operand_rel16]; rel_bytes = 2; }
if (imm) {
U1 imm16 = slot[x8616_operand_imm16] != 0;
U1 imm8 = slot[x8616_operand_imm8] != 0;
imm->immediate_bytes = imm16 ? 2 : (imm8 || w == x8616_w_byte || s ? 1 : 2);
}
if (rel) {
U1 size = x8616_encode_prefix_count(inst) + 1 + rel_bytes;
rel->displacement = s2_(rel->displacement - s2_(size));
rel->displacement_bytes = rel_bytes;
}
inst->header = header;
inst->mod_rm = modrm;
inst->has_mod_rm = has_modrm;
inst->post_opcode = best->post_opcode.mask ? best->post_opcode.bits : 0;
return 1;
}
internal X8616_EncodeStatus internal X8616_EncodeStatus
x8616_encode_instruction(Str8Gen_R gen, X8616_DecodedInstruction_R inst) x8616_encode_instruction(Str8Gen_R gen, X8616_DecodedInstruction_R inst)
{ {
B4 bad = inst->decode_flags & (x8616_decode_invalid | x8616_decode_truncated); if (inst->decode_flags & (x8616_decode_invalid | x8616_decode_truncated)) return x8616_encode_invalid_record;
bad |= inst->size == 0; X8616_DecodedInstruction local = *inst;
if (bad) return x8616_encode_invalid_record; if (local.size == 0) {
if (x8616_encode_assemble(& local) == 0) return x8616_encode_invalid_record;
}
U1 buf[16]; U1 buf[16];
U1 n = 0; U1 n = 0;
U1 rep = inst->prefixes.repeat == x8616_rep ? x8616_rep_prefix() : x8616_repne_prefix(); U1 rep = local.prefixes.repeat == x8616_rep ? x8616_rep_prefix() : x8616_repne_prefix();
if (inst->prefixes.lock) { x8616_encode_buf_u1(buf, & n, x8616_lock_prefix()); } if (local.prefixes.lock) { x8616_encode_buf_u1(buf, & n, x8616_lock_prefix()); }
if (inst->prefixes.has_repeat) { x8616_encode_buf_u1(buf, & n, rep); } if (local.prefixes.has_repeat) { x8616_encode_buf_u1(buf, & n, rep); }
if (inst->prefixes.has_segment) { x8616_encode_buf_u1(buf, & n, x8616_segment_prefix(inst->prefixes.segment)); } if (local.prefixes.has_segment) { x8616_encode_buf_u1(buf, & n, x8616_segment_prefix(local.prefixes.segment)); }
x8616_encode_buf_u1(buf, & n, inst->header); x8616_encode_buf_u1(buf, & n, local.header);
if (inst->post_opcode) { x8616_encode_buf_u1(buf, & n, inst->post_opcode); } if (local.post_opcode) { x8616_encode_buf_u1(buf, & n, local.post_opcode); }
if (inst->has_mod_rm) { x8616_encode_buf_u1(buf, & n, inst->mod_rm); } if (local.has_mod_rm) { x8616_encode_buf_u1(buf, & n, local.mod_rm); }
for (U1 id = 0; id < inst->operand_count; ++id) { for (U1 id = 0; id < local.operand_count; ++id) {
X8616_DecodedOperand_R op = inst->operands + id; X8616_DecodedOperand_R op = local.operands + id;
if ((op->flags & x8616_decoded_operand_memory) == 0) continue; if ((op->flags & x8616_decoded_operand_memory) == 0) continue;
if ( op->flags & x8616_decoded_operand_direct) x8616_encode_buf_u2(buf, & n, op->address); if ( op->flags & x8616_decoded_operand_direct) x8616_encode_buf_u2(buf, & n, op->address);
else x8616_encode_buf_disp(buf, & n, op->displacement, op->displacement_bytes); else x8616_encode_buf_disp(buf, & n, op->displacement, op->displacement_bytes);
} }
for (U1 id = 0; id < inst->operand_count; ++id) { for (U1 id = 0; id < local.operand_count; ++id) {
X8616_DecodedOperand_R op = inst->operands + id; X8616_DecodedOperand_R op = local.operands + id;
B4 op_rel = op->flags & x8616_decoded_operand_relative; B4 op_rel = op->flags & x8616_decoded_operand_relative;
B4 op_imm = (op->flags & x8616_decoded_operand_immediate) && op->immediate_bytes; B4 op_imm = (op->flags & x8616_decoded_operand_immediate) && op->immediate_bytes;
B4 op_far = op->flags & x8616_decoded_operand_far_ptr; B4 op_far = op->flags & x8616_decoded_operand_far_ptr;