mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-19 08:32:33 +00:00
x86: Precompute the explicit_count and has_implicit in the Encoding_Flags
This commit is contained in:
@@ -706,16 +706,20 @@ encoding_matches_inline :: proc "contextless" (inst: ^Instruction, enc: ^Encodin
|
||||
// when not in Mode._32.
|
||||
if enc.flags.mode_32_only && mode != ._32 { return false }
|
||||
|
||||
// Count non-implicit encoding operands
|
||||
encoding_operand_count: u8 = 0
|
||||
for op_type in enc.ops {
|
||||
if op_type == .NONE { break }
|
||||
if !is_implicit_op_inline(op_type) { encoding_operand_count += 1 }
|
||||
explicit_count := enc.flags.explicit_count
|
||||
|
||||
if !enc.flags.has_implicit {
|
||||
if inst.operand_count != explicit_count { return false }
|
||||
for i in 0 ..< explicit_count {
|
||||
eff := mode_rewrite_op_type(enc.ops[i], mode, enc.flags.default_64)
|
||||
operand_matches_inline(&inst.ops[i], eff) or_return
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Special case: if user provides exactly one more operand than non-implicit count,
|
||||
// check if the extra operand matches an implicit operand (e.g., CL for shifts)
|
||||
if inst.operand_count == encoding_operand_count + 1 {
|
||||
if inst.operand_count == explicit_count + 1 {
|
||||
// Check if the last user operand matches an implicit operand in the encoding
|
||||
last_user_op := &inst.ops[inst.operand_count - 1]
|
||||
found_matching_implicit := false
|
||||
@@ -743,7 +747,7 @@ encoding_matches_inline :: proc "contextless" (inst: ^Instruction, enc: ^Encodin
|
||||
}
|
||||
|
||||
// STandard case: operand count must match non-implicit count
|
||||
if inst.operand_count != encoding_operand_count { return false }
|
||||
if inst.operand_count != explicit_count { return false }
|
||||
|
||||
// Match each user operand against non-implicit encoding operands
|
||||
user_idx: u8 = 0
|
||||
|
||||
@@ -246,18 +246,20 @@ VEX_L :: enum u8 {
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Encoding_Flags :: bit_field u32 {
|
||||
esc: Escape | 2, // escape sequence
|
||||
prefix: u8 | 2, // mandatory prefix: 0=none, 1=66, 2=F3, 3=F2
|
||||
vex_type: VEX_Type | 2, // VEX/EVEX/XOP
|
||||
vex_w: VEX_W | 2, // VEX.W requirement
|
||||
vex_l: VEX_L | 2, // VEX.L requirement
|
||||
default_64: bool | 1, // default to 64-bit operand size (PUSH, POP, etc.)
|
||||
force_rex_w: bool | 1, // always emit REX.W
|
||||
no_rex: bool | 1, // REX prefix not allowed (high byte regs)
|
||||
lock_ok: bool | 1, // LOCK prefix valid
|
||||
rep_ok: bool | 1, // REP prefix valid
|
||||
modrm_reg_ext: bool | 1, // ModR/M reg field is opcode extension (use ext field)
|
||||
mode_32_only: bool | 1, // only valid in Mode._32 (e.g. short-form INC/DEC at 0x40-0x4F)
|
||||
esc: Escape | 2, // escape sequence
|
||||
prefix: u8 | 2, // mandatory prefix: 0=none, 1=66, 2=F3, 3=F2
|
||||
vex_type: VEX_Type | 2, // VEX/EVEX/XOP
|
||||
vex_w: VEX_W | 2, // VEX.W requirement
|
||||
vex_l: VEX_L | 2, // VEX.L requirement
|
||||
default_64: bool | 1, // default to 64-bit operand size (PUSH, POP, etc.)
|
||||
force_rex_w: bool | 1, // always emit REX.W
|
||||
no_rex: bool | 1, // REX prefix not allowed (high byte regs)
|
||||
lock_ok: bool | 1, // LOCK prefix valid
|
||||
rep_ok: bool | 1, // REP prefix valid
|
||||
modrm_reg_ext: bool | 1, // ModR/M reg field is opcode extension (use ext field)
|
||||
mode_32_only: bool | 1, // only valid in Mode._32 (e.g. short-form INC/DEC at 0x40-0x4F)
|
||||
explicit_count: u8 | 3, // 0..<4 non-implicit operands
|
||||
has_implicit: bool | 1, // any implicit operand
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -135,7 +135,7 @@ write_encoding :: proc(sb: ^strings.Builder, e: lib.Encoding, max_name: int) {
|
||||
for en, i in e.enc { print_enum_buffered(sb, en, 4, i+1 < len(e.enc)) }
|
||||
strings.write_string(sb, "}, ")
|
||||
fmt.sbprintf(sb, "0x%02X, %d, ", e.opcode, e.ext)
|
||||
write_flags(sb, e.flags)
|
||||
write_flags(sb, e, e.flags)
|
||||
strings.write_string(sb, "},\n")
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ gen_entries :: proc(sb: ^strings.Builder, name, typ: string, entries: []Collecte
|
||||
strings.write_string(sb, "}, {")
|
||||
for en, i in e.enc { print_enum_buffered(sb, en, 4, i+1 < len(e.enc)) }
|
||||
strings.write_string(sb, "}, ")
|
||||
write_flags(sb, e.flags)
|
||||
write_flags(sb, nil, e.flags)
|
||||
strings.write_string(sb, "},\n")
|
||||
}
|
||||
strings.write_string(sb, "}\n\n")
|
||||
@@ -366,7 +366,7 @@ print_enum_buffered :: proc(sb: ^strings.Builder, x: $T, max_name: int, comma: b
|
||||
|
||||
// Complete Encoding_Flags emitter -- every field, so ENCODE_FORMS round-trips
|
||||
// the SoT exactly (mode_32_only is read by the encoder).
|
||||
write_flags :: proc(sb: ^strings.Builder, flags: lib.Encoding_Flags) {
|
||||
write_flags :: proc(sb: ^strings.Builder, enc: Maybe(Encoding), flags: lib.Encoding_Flags) {
|
||||
parts: [dynamic]string
|
||||
defer delete(parts)
|
||||
if flags.esc != .NONE { append(&parts, fmt.tprintf("esc=.%v", flags.esc)) }
|
||||
@@ -381,6 +381,26 @@ write_flags :: proc(sb: ^strings.Builder, flags: lib.Encoding_Flags) {
|
||||
if flags.rep_ok { append(&parts, "rep_ok=true") }
|
||||
if flags.modrm_reg_ext { append(&parts, "modrm_reg_ext=true") }
|
||||
if flags.mode_32_only { append(&parts, "mode_32_only=true") }
|
||||
|
||||
if e, ok := enc.?; ok {
|
||||
encoding_operand_count: u8 = 0
|
||||
has_implict := false
|
||||
for op_type in e.ops {
|
||||
if op_type == .NONE { break }
|
||||
if lib.is_implicit_op_inline(op_type) {
|
||||
has_implict = true
|
||||
} else {
|
||||
encoding_operand_count += 1
|
||||
}
|
||||
}
|
||||
if encoding_operand_count > 0 {
|
||||
append(&parts, fmt.tprintf("explicit_count=%d", encoding_operand_count))
|
||||
}
|
||||
if has_implict {
|
||||
append(&parts, "has_implict=true")
|
||||
}
|
||||
}
|
||||
|
||||
strings.write_string(sb, "{")
|
||||
for part, i in parts {
|
||||
if i > 0 { strings.write_string(sb, ", ") }
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user