lib/isa/src/x86/decode.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

   1 const std = @import("std");
   2 const x86 = @import("root.zig");
   3 
   4 pub const Error = error{
   5     AmbiguousPrefix,
   6     InstructionTooLong,
   7     InvalidEncoding,
   8     TruncatedInstruction,
   9     UnsupportedAddressSize,
  10     UnsupportedOpcode,
  11     UnsupportedPrefix,
  12 };
  13 
  14 const Selector = enum {
  15     none,
  16     extension,
  17 };
  18 
  19 const Encoding = struct {
  20     modrm: bool = false,
  21     selector: Selector = .none,
  22 };
  23 
  24 const Bank = enum {
  25     none,
  26     gpr,
  27     vector,
  28     selector,
  29 };
  30 
  31 const Embedded = enum {
  32     none,
  33     accumulator,
  34     opcode,
  35 };
  36 
  37 const Shape = struct {
  38     register_bank: Bank = .none,
  39     register_access: x86.Access = .none,
  40     register_high8: bool = false,
  41     operand_bank: Bank = .none,
  42     operand_access: x86.Access = .none,
  43     operand_high8: bool = false,
  44     operand_width: ?x86.Width = null,
  45     embedded: Embedded = .none,
  46     embedded_access: x86.Access = .none,
  47 };
  48 
  49 const PrefixState = struct {
  50     form: x86.Prefix,
  51     rex: u8,
  52     segment: x86.Segment,
  53 
  54     fn wide(self: PrefixState) bool {
  55         return self.rex & 0x08 != 0;
  56     }
  57 
  58     fn rexR(self: PrefixState) u4 {
  59         return if (self.rex & 0x04 != 0) 8 else 0;
  60     }
  61 
  62     fn rexX(self: PrefixState) u4 {
  63         return if (self.rex & 0x02 != 0) 8 else 0;
  64     }
  65 
  66     fn rexB(self: PrefixState) u4 {
  67         return if (self.rex & 0x01 != 0) 8 else 0;
  68     }
  69 };
  70 
  71 const ModRm = struct {
  72     mode: x86.Mode,
  73     mode_raw: u2,
  74     extension: u3,
  75     register: u4,
  76     operand: u4,
  77     base: ?u4,
  78     index: ?u4,
  79     scale: x86.Scale,
  80     displacement: i32,
  81     displacement_bytes: u3,
  82     address: x86.AddressKind,
  83     segment: x86.Segment,
  84 };
  85 
  86 const Payload = struct {
  87     immediate: ?x86.Immediate = null,
  88     relative: ?i32 = null,
  89 };
  90 
  91 pub fn decode(code: []const u8) Error!x86.Instruction {
  92     var diagnostic: x86.Diagnostic = .{};
  93     return decodeWithDiagnostic(code, &diagnostic);
  94 }
  95 
  96 pub fn decodeWithDiagnostic(
  97     code: []const u8,
  98     diagnostic: *x86.Diagnostic,
  99 ) Error!x86.Instruction {
 100     diagnostic.* = .{};
 101     var cursor: usize = 0;
 102     const prefix = try parsePrefix(code, &cursor, diagnostic);
 103     const first = try takeByte(code, &cursor);
 104     const map: x86.Map = if (first == 0x0f) .two else .one;
 105     const opcode = if (map == .two) try takeByte(code, &cursor) else first;
 106     const instruction_encoding = encoding(map, opcode) orelse {
 107         const candidate = x86.Form{ .prefix = prefix.form, .map = map, .opcode = opcode };
 108         diagnostic.captureForm(candidate);
 109         return error.UnsupportedOpcode;
 110     };
 111     var modrm = if (instruction_encoding.modrm)
 112         try parseModRm(code, &cursor, prefix)
 113     else
 114         null;
 115     var form = createForm(prefix, map, opcode, instruction_encoding, modrm);
 116     const operation = operationFor(prefix, map, opcode, modrm) orelse {
 117         diagnostic.captureForm(form);
 118         return error.UnsupportedOpcode;
 119     };
 120     if (modrm) |*value| {
 121         parseDisplacement(code, &cursor, value) catch |failure| {
 122             diagnostic.captureForm(form);
 123             return failure;
 124         };
 125     }
 126     const payload = parsePayload(code, &cursor, prefix, map, opcode, modrm) catch |failure| {
 127         if (!(map == .one and opcode == 0xcd)) diagnostic.captureForm(form);
 128         return failure;
 129     };
 130     if (map == .one and opcode == 0xcd) {
 131         form.immediate = @truncate(payload.immediate.?.value);
 132     }
 133     if (cursor > 15) return error.InstructionTooLong;
 134     var result = createInstruction(form, operation, cursor, prefix, modrm, payload);
 135     addImplicitOperands(&result, prefix);
 136     return result;
 137 }
 138 
 139 fn parsePrefix(
 140     code: []const u8,
 141     cursor: *usize,
 142     diagnostic: *x86.Diagnostic,
 143 ) Error!PrefixState {
 144     while (cursor.* < code.len and cursor.* < 15) {
 145         const byte = code[cursor.*];
 146         if (byte == 0x67) {
 147             diagnostic.capturePrefix(code[0 .. cursor.* + 1]);
 148             return error.UnsupportedAddressSize;
 149         }
 150         if (!prefixByte(byte)) break;
 151         cursor.* += 1;
 152     }
 153     if (cursor.* == 15) return error.TruncatedInstruction;
 154     const bytes = code[0..cursor.*];
 155     const form = x86.Prefix.fromBytes(bytes) orelse {
 156         diagnostic.capturePrefix(bytes);
 157         return prefixError(bytes);
 158     };
 159     return .{
 160         .form = form,
 161         .rex = form.rexByte(),
 162         .segment = segmentFor(bytes),
 163     };
 164 }
 165 
 166 fn prefixByte(byte: u8) bool {
 167     return switch (byte) {
 168         0x26,
 169         0x2e,
 170         0x36,
 171         0x3e,
 172         0x64,
 173         0x65,
 174         0x66,
 175         0xf0,
 176         0xf2,
 177         0xf3,
 178         0x40...0x4f,
 179         => true,
 180         else => false,
 181     };
 182 }
 183 
 184 fn prefixError(bytes: []const u8) Error {
 185     if (operand16CsSequence(bytes)) return error.UnsupportedPrefix;
 186     var operand16 = false;
 187     var lock = false;
 188     var repeat = false;
 189     var segment = false;
 190     var rex = false;
 191     for (bytes) |byte| {
 192         if (byte >= 0x40 and byte <= 0x4f) {
 193             if (rex) return error.AmbiguousPrefix;
 194             rex = true;
 195             continue;
 196         }
 197         if (rex) return error.AmbiguousPrefix;
 198         switch (byte) {
 199             0x66 => {
 200                 if (operand16) return error.AmbiguousPrefix;
 201                 operand16 = true;
 202             },
 203             0xf0 => {
 204                 if (lock) return error.AmbiguousPrefix;
 205                 lock = true;
 206             },
 207             0xf2, 0xf3 => {
 208                 if (repeat) return error.AmbiguousPrefix;
 209                 repeat = true;
 210             },
 211             0x26, 0x2e, 0x36, 0x3e, 0x64, 0x65 => {
 212                 if (segment) return error.AmbiguousPrefix;
 213                 segment = true;
 214             },
 215             else => {},
 216         }
 217     }
 218     return error.UnsupportedPrefix;
 219 }
 220 
 221 fn operand16CsSequence(bytes: []const u8) bool {
 222     if (bytes.len < 2 or bytes[bytes.len - 1] != 0x2e) return false;
 223     for (bytes[0 .. bytes.len - 1]) |byte| {
 224         if (byte != 0x66) return false;
 225     }
 226     return true;
 227 }
 228 
 229 fn segmentFor(bytes: []const u8) x86.Segment {
 230     for (bytes) |byte| {
 231         return switch (byte) {
 232             0x26 => .es,
 233             0x2e => .cs,
 234             0x36 => .ss,
 235             0x3e => .ds,
 236             0x64 => .fs,
 237             0x65 => .gs,
 238             else => continue,
 239         };
 240     }
 241     return .none;
 242 }
 243 
 244 fn encoding(map: x86.Map, opcode: u8) ?Encoding {
 245     return switch (map) {
 246         .one => encodingOne(opcode),
 247         .two => encodingTwo(opcode),
 248     };
 249 }
 250 
 251 fn encodingOne(opcode: u8) ?Encoding {
 252     if (groupOpcode(opcode)) return .{ .modrm = true, .selector = .extension };
 253     if (plainModRmOpcode(opcode)) return .{ .modrm = true };
 254     if (x86.formModeled(.{ .opcode = opcode })) return .{};
 255     return null;
 256 }
 257 
 258 fn groupOpcode(opcode: u8) bool {
 259     return switch (opcode) {
 260         0x80,
 261         0x81,
 262         0x83,
 263         0xc0,
 264         0xc1,
 265         0xc6,
 266         0xc7,
 267         0xd0,
 268         0xd1,
 269         0xd2,
 270         0xd3,
 271         0xf6,
 272         0xf7,
 273         0xfe,
 274         0xff,
 275         => true,
 276         else => false,
 277     };
 278 }
 279 
 280 fn plainModRmOpcode(opcode: u8) bool {
 281     if (opcode <= 0x03) return true;
 282     if (opcode >= 0x08 and opcode <= 0x0b) return true;
 283     if (opcode >= 0x18 and opcode <= 0x1b) return true;
 284     if (opcode >= 0x20 and opcode <= 0x23) return true;
 285     if (opcode >= 0x28 and opcode <= 0x2b) return true;
 286     if (opcode >= 0x30 and opcode <= 0x33) return true;
 287     return switch (opcode) {
 288         0x38,
 289         0x39,
 290         0x3b,
 291         0x69,
 292         0x6b,
 293         0x84,
 294         0x85,
 295         0x88,
 296         0x89,
 297         0x8a,
 298         0x8b,
 299         0x8d,
 300         => true,
 301         else => false,
 302     };
 303 }
 304 
 305 fn encodingTwo(opcode: u8) ?Encoding {
 306     if (opcode == 0x1f or opcode == 0x90 or
 307         ((opcode >= 0x92 and opcode <= 0x97) or
 308             (opcode >= 0x9c and opcode <= 0x9f)))
 309     {
 310         return .{ .modrm = true, .selector = .extension };
 311     }
 312     if (switch (opcode) {
 313         0x10,
 314         0x11,
 315         0x42,
 316         0x43,
 317         0x44,
 318         0x45,
 319         0x47,
 320         0x6f,
 321         0x70,
 322         0x7f,
 323         0xaf,
 324         0xb0,
 325         0xb6,
 326         0xb7,
 327         0xbe,
 328         0xbf,
 329         => true,
 330         else => false,
 331     }) return .{ .modrm = true };
 332     if (x86.formModeled(.{ .map = .two, .opcode = opcode })) return .{};
 333     return null;
 334 }
 335 
 336 fn parseModRm(
 337     code: []const u8,
 338     cursor: *usize,
 339     prefix: PrefixState,
 340 ) Error!ModRm {
 341     const byte = try takeByte(code, cursor);
 342     const mode_raw: u2 = @intCast(byte >> 6);
 343     const extension: u3 = @intCast((byte >> 3) & 7);
 344     const operand_raw: u3 = @intCast(byte & 7);
 345     var result = ModRm{
 346         .mode = modeFromRaw(mode_raw),
 347         .mode_raw = mode_raw,
 348         .extension = extension,
 349         .register = @as(u4, extension) | prefix.rexR(),
 350         .operand = @as(u4, operand_raw) | prefix.rexB(),
 351         .base = null,
 352         .index = null,
 353         .scale = .one,
 354         .displacement = 0,
 355         .displacement_bytes = 0,
 356         .address = .none,
 357         .segment = prefix.segment,
 358     };
 359     if (mode_raw == 3) return result;
 360     if (operand_raw == 4) {
 361         try parseSib(code, cursor, prefix, &result);
 362     } else if (mode_raw == 0 and operand_raw == 5) {
 363         result.address = .rip_relative;
 364         result.displacement_bytes = 4;
 365     } else {
 366         result.base = result.operand;
 367         result.address = .base;
 368     }
 369     if (mode_raw == 1) result.displacement_bytes = 1;
 370     if (mode_raw == 2) result.displacement_bytes = 4;
 371     return result;
 372 }
 373 
 374 fn parseSib(
 375     code: []const u8,
 376     cursor: *usize,
 377     prefix: PrefixState,
 378     result: *ModRm,
 379 ) Error!void {
 380     const sib = try takeByte(code, cursor);
 381     result.scale = @fromBackingInt(@intCast(@as(u2, @intCast(sib >> 6))));
 382     const index_raw: u3 = @intCast((sib >> 3) & 7);
 383     const base_raw: u3 = @intCast(sib & 7);
 384     if (index_raw != 4 or prefix.rexX() != 0) {
 385         result.index = @as(u4, index_raw) | prefix.rexX();
 386     }
 387     if (result.mode_raw == 0 and base_raw == 5) {
 388         result.displacement_bytes = 4;
 389     } else {
 390         result.base = @as(u4, base_raw) | prefix.rexB();
 391     }
 392     result.address = if (result.base == null)
 393         if (result.index == null) .absolute else .absolute_indexed
 394     else if (result.index == null)
 395         .base
 396     else
 397         .base_indexed;
 398 }
 399 
 400 fn parseDisplacement(
 401     code: []const u8,
 402     cursor: *usize,
 403     modrm: *ModRm,
 404 ) Error!void {
 405     modrm.displacement = switch (modrm.displacement_bytes) {
 406         0 => 0,
 407         1 => try readI8(code, cursor),
 408         4 => try readI32(code, cursor),
 409         else => return error.InvalidEncoding,
 410     };
 411 }
 412 
 413 fn createForm(
 414     prefix: PrefixState,
 415     map: x86.Map,
 416     opcode: u8,
 417     instruction_encoding: Encoding,
 418     modrm: ?ModRm,
 419 ) x86.Form {
 420     var result = x86.Form{
 421         .prefix = prefix.form,
 422         .map = map,
 423         .opcode = opcode,
 424         .width = effectiveWidth(prefix.form, map, opcode),
 425     };
 426     const shape_value = shape(map, opcode, if (modrm) |value| value.extension else null);
 427     if (modrm) |value| {
 428         result.mode = value.mode;
 429         result.address = value.address;
 430         result.base_role = addressRole(value.base);
 431         result.index_role = addressRole(value.index);
 432         if (instruction_encoding.selector == .extension) {
 433             result.extension = .fromRaw(value.extension);
 434         }
 435         applyOperands(&result, prefix, shape_value, value);
 436     }
 437     applyEmbedded(&result, prefix, shape_value, opcode);
 438     return result;
 439 }
 440 
 441 fn effectiveWidth(prefix: x86.Prefix, map: x86.Map, opcode: u8) x86.Width {
 442     return switch (map) {
 443         .one => oneByteWidth(prefix, opcode),
 444         .two => twoByteWidth(prefix, opcode),
 445     };
 446 }
 447 
 448 fn oneByteWidth(prefix: x86.Prefix, opcode: u8) x86.Width {
 449     if (switch (opcode) {
 450         0x90, 0x9c, 0xcd, 0xf4, 0xf5, 0xfa, 0xfb => true,
 451         else => false,
 452     }) return .none;
 453     if ((opcode >= 0x50 and opcode <= 0x5f) or
 454         ((opcode >= 0x72 and opcode <= 0x77) or
 455             (opcode >= 0x7c and opcode <= 0x7f)) or
 456         switch (opcode) {
 457             0x6a, 0xc3, 0xe8, 0xe9, 0xeb => true,
 458             else => false,
 459         }) return controlWidth(prefix);
 460     if (byteOpcode(opcode)) return .byte;
 461     return operandWidth(prefix);
 462 }
 463 
 464 fn byteOpcode(opcode: u8) bool {
 465     if (opcode >= 0xb0 and opcode <= 0xb7) return true;
 466     return switch (opcode) {
 467         0x00,
 468         0x02,
 469         0x04,
 470         0x08,
 471         0x0a,
 472         0x18,
 473         0x1a,
 474         0x1c,
 475         0x20,
 476         0x22,
 477         0x24,
 478         0x28,
 479         0x2a,
 480         0x2c,
 481         0x30,
 482         0x32,
 483         0x34,
 484         0x38,
 485         0x3c,
 486         0x80,
 487         0x84,
 488         0x88,
 489         0x8a,
 490         0xa4,
 491         0xa8,
 492         0xaa,
 493         0xc0,
 494         0xc6,
 495         0xd0,
 496         0xd2,
 497         0xee,
 498         0xf6,
 499         0xfe,
 500         => true,
 501         else => false,
 502     };
 503 }
 504 
 505 fn twoByteWidth(prefix: x86.Prefix, opcode: u8) x86.Width {
 506     if (switch (opcode) {
 507         0x0b, 0x1f, 0x30, 0x32, 0xa2 => true,
 508         else => false,
 509     }) return .none;
 510     if (switch (opcode) {
 511         0x10, 0x11, 0x6f, 0x70, 0x7f => true,
 512         else => false,
 513     }) return .vector128;
 514     if ((opcode >= 0x82 and opcode <= 0x87) or
 515         (opcode >= 0x8c and opcode <= 0x8f)) return controlWidth(prefix);
 516     if (opcode == 0x90 or ((opcode >= 0x92 and opcode <= 0x97) or
 517         (opcode >= 0x9c and opcode <= 0x9f)) or opcode == 0xb0)
 518     {
 519         return .byte;
 520     }
 521     if (opcode == 0xb6 or opcode == 0xb7 or opcode == 0xbe or opcode == 0xbf) {
 522         return if (prefix.wide())
 523             .qword
 524         else if (prefix.hasOperand16())
 525             .word
 526         else
 527             .dword;
 528     }
 529     return operandWidth(prefix);
 530 }
 531 
 532 fn operandWidth(prefix: x86.Prefix) x86.Width {
 533     if (prefix.wide()) return .qword;
 534     if (prefix.hasOperand16()) return .word;
 535     return .dword;
 536 }
 537 
 538 fn controlWidth(prefix: x86.Prefix) x86.Width {
 539     return if (prefix.hasOperand16()) .word else .qword;
 540 }
 541 
 542 fn shape(map: x86.Map, opcode: u8, extension: ?u3) Shape {
 543     return switch (map) {
 544         .one => shapeOne(opcode, extension),
 545         .two => shapeTwo(opcode),
 546     };
 547 }
 548 
 549 fn shapeOne(opcode: u8, extension: ?u3) Shape {
 550     if (opcode < 0x80) return shapeOneLow(opcode);
 551     return shapeOneHigh(opcode, extension);
 552 }
 553 
 554 fn shapeOneLow(opcode: u8) Shape {
 555     return switch (opcode) {
 556         0x00, 0x08, 0x18, 0x20, 0x28, 0x30 => gpr(.read, .read_write, true),
 557         0x01, 0x09, 0x19, 0x21, 0x29, 0x31 => gpr(.read, .read_write, false),
 558         0x02, 0x0a, 0x1a, 0x22, 0x2a, 0x32 => gpr(.read_write, .read, true),
 559         0x03, 0x0b, 0x1b, 0x23, 0x2b, 0x33 => gpr(.read_write, .read, false),
 560         0x38 => gpr(.read, .read, true),
 561         0x39, 0x3b => gpr(.read, .read, false),
 562         0x04,
 563         0x05,
 564         0x0d,
 565         0x1c,
 566         0x1d,
 567         0x24,
 568         0x25,
 569         0x2c,
 570         0x2d,
 571         0x34,
 572         0x35,
 573         => embedded(.accumulator, .read_write),
 574         0x3c, 0x3d => embedded(.accumulator, .read),
 575         0x50...0x57 => embedded(.opcode, .read),
 576         0x58...0x5f => embedded(.opcode, .write),
 577         0x69, 0x6b => gpr(.write, .read, false),
 578         else => .{},
 579     };
 580 }
 581 
 582 fn shapeOneHigh(opcode: u8, extension: ?u3) Shape {
 583     const byte_group = opcode == 0xc0 or opcode == 0xfe;
 584     return switch (opcode) {
 585         0x80 => group(groupAccess(extension), true),
 586         0x81, 0x83 => group(groupAccess(extension), false),
 587         0x84 => gpr(.read, .read, true),
 588         0x85 => gpr(.read, .read, false),
 589         0x88 => gpr(.read, .write, true),
 590         0x89 => gpr(.read, .write, false),
 591         0x8a => gpr(.write, .read, true),
 592         0x8b => gpr(.write, .read, false),
 593         0x8d => gpr(.write, .none, false),
 594         0xa8, 0xa9 => embedded(.accumulator, .read),
 595         0xb0...0xbf => embedded(.opcode, .write),
 596         0xc0, 0xc1, 0xd0, 0xd1, 0xd2, 0xd3, 0xfe => group(.read_write, byte_group),
 597         0xc6, 0xc7 => group(.write, opcode == 0xc6),
 598         0xf6, 0xf7 => group(groupThreeAccess(extension), opcode == 0xf6),
 599         0xff => groupFiveShape(extension),
 600         else => .{},
 601     };
 602 }
 603 
 604 fn shapeTwo(opcode: u8) Shape {
 605     return switch (opcode) {
 606         0x10, 0x6f, 0x70 => vector(.read),
 607         0x11, 0x7f => vector(.write),
 608         0x42...0x45, 0x47 => gpr(.read_write, .read, false),
 609         0x90, 0x92...0x97, 0x9c...0x9f => group(.write, true),
 610         0xaf => gpr(.read_write, .read, false),
 611         0xb0 => gpr(.read, .read_write, true),
 612         0xb6, 0xbe => gprMixed(.write, .read, .byte),
 613         0xb7, 0xbf => gprMixed(.write, .read, .word),
 614         0xc8...0xcf => embedded(.opcode, .write),
 615         else => .{},
 616     };
 617 }
 618 
 619 fn gpr(register_access: x86.Access, operand_access: x86.Access, byte: bool) Shape {
 620     return .{
 621         .register_bank = .gpr,
 622         .register_access = register_access,
 623         .register_high8 = byte,
 624         .operand_bank = .gpr,
 625         .operand_access = operand_access,
 626         .operand_high8 = byte,
 627     };
 628 }
 629 
 630 fn gprMixed(
 631     register_access: x86.Access,
 632     operand_access: x86.Access,
 633     operand_width: x86.Width,
 634 ) Shape {
 635     return .{
 636         .register_bank = .gpr,
 637         .register_access = register_access,
 638         .operand_bank = .gpr,
 639         .operand_access = operand_access,
 640         .operand_high8 = operand_width == .byte,
 641         .operand_width = operand_width,
 642     };
 643 }
 644 
 645 fn group(access: x86.Access, byte: bool) Shape {
 646     return .{
 647         .register_bank = .selector,
 648         .operand_bank = .gpr,
 649         .operand_access = access,
 650         .operand_high8 = byte,
 651     };
 652 }
 653 
 654 fn groupFiveShape(extension: ?u3) Shape {
 655     var result = group(groupFiveAccess(extension), false);
 656     if (extension == 2 or extension == 4) result.operand_width = .qword;
 657     return result;
 658 }
 659 
 660 fn vector(access: x86.Access) Shape {
 661     return .{
 662         .register_bank = .vector,
 663         .register_access = if (access == .read) .write else .read,
 664         .operand_bank = .vector,
 665         .operand_access = access,
 666     };
 667 }
 668 
 669 fn embedded(kind: Embedded, access: x86.Access) Shape {
 670     return .{ .embedded = kind, .embedded_access = access };
 671 }
 672 
 673 fn groupAccess(extension: ?u3) x86.Access {
 674     return if (extension == 7) .read else .read_write;
 675 }
 676 
 677 fn groupThreeAccess(extension: ?u3) x86.Access {
 678     return switch (extension orelse 0) {
 679         2, 3 => .read_write,
 680         else => .read,
 681     };
 682 }
 683 
 684 fn groupFiveAccess(extension: ?u3) x86.Access {
 685     return switch (extension orelse 0) {
 686         0, 1 => .read_write,
 687         else => .read,
 688     };
 689 }
 690 
 691 fn applyOperands(
 692     result: *x86.Form,
 693     prefix: PrefixState,
 694     shape_value: Shape,
 695     modrm: ModRm,
 696 ) void {
 697     if (shape_value.register_bank == .gpr) {
 698         const register = gprRegister(
 699             modrm.register,
 700             result.width,
 701             prefix,
 702             shape_value.register_high8,
 703         );
 704         result.register_role = register.role();
 705         result.register_access = shape_value.register_access;
 706     }
 707     if (modrm.mode == .register and shape_value.operand_bank == .gpr) {
 708         const width = operandWidthFor(result.*, shape_value);
 709         const operand = gprRegister(modrm.operand, width, prefix, shape_value.operand_high8);
 710         result.operand_role = operand.role();
 711     }
 712     result.operand_access = if (shape_value.operand_bank == .vector and
 713         modrm.mode == .register)
 714         .none
 715     else
 716         shape_value.operand_access;
 717 }
 718 
 719 fn applyEmbedded(
 720     result: *x86.Form,
 721     prefix: PrefixState,
 722     shape_value: Shape,
 723     opcode: u8,
 724 ) void {
 725     result.embedded_access = shape_value.embedded_access;
 726     const register = switch (shape_value.embedded) {
 727         .none => return,
 728         .accumulator => gprRegister(0, result.width, prefix, result.width == .byte),
 729         .opcode => gprRegister(
 730             @as(u4, @intCast(opcode & 7)) | prefix.rexB(),
 731             result.width,
 732             prefix,
 733             result.width == .byte,
 734         ),
 735     };
 736     result.embedded_role = register.role();
 737 }
 738 
 739 fn operandWidthFor(form: x86.Form, shape_value: Shape) x86.Width {
 740     return shape_value.operand_width orelse form.width;
 741 }
 742 
 743 fn addressRole(value: ?u4) x86.Role {
 744     const number = value orelse return .none;
 745     return (x86.Register{ .number = number, .lane = .qword }).role();
 746 }
 747 
 748 fn operationFor(
 749     prefix: PrefixState,
 750     map: x86.Map,
 751     opcode: u8,
 752     modrm: ?ModRm,
 753 ) ?x86.Operation {
 754     return switch (map) {
 755         .one => operationOne(
 756             prefix,
 757             opcode,
 758             if (modrm) |value| value.extension else null,
 759         ),
 760         .two => operationTwo(
 761             prefix,
 762             opcode,
 763             if (modrm) |value| value.extension else null,
 764         ),
 765     };
 766 }
 767 
 768 fn operationOne(
 769     prefix: PrefixState,
 770     opcode: u8,
 771     extension: ?u3,
 772 ) ?x86.Operation {
 773     if (arithmeticOperation(opcode)) |operation| return operation;
 774     if (opcode >= 0x50 and opcode <= 0x57) return .push;
 775     if (opcode >= 0x58 and opcode <= 0x5f) return .pop;
 776     if ((opcode >= 0x72 and opcode <= 0x77) or
 777         (opcode >= 0x7c and opcode <= 0x7f)) return conditionOperation(opcode & 0x0f);
 778     if (opcode >= 0xb0 and opcode <= 0xbf) return .mov;
 779     return switch (opcode) {
 780         0x69, 0x6b => .imul,
 781         0x6a => .push,
 782         0x80, 0x81, 0x83 => groupOneOperation(extension),
 783         0x84, 0x85, 0xa8, 0xa9 => .test_,
 784         0x88...0x8b => .mov,
 785         0xc6, 0xc7 => if (extension == 0) .mov else null,
 786         0x8d => .lea,
 787         0x90 => if (prefix.form.hasOperand16() or prefix.rexB() != 0)
 788             .xchg
 789         else
 790             .nop,
 791         0x9c => .pushf,
 792         0xa4, 0xa5 => .movs,
 793         0xaa, 0xab => .stos,
 794         0xc0, 0xc1, 0xd0, 0xd1, 0xd2, 0xd3 => shiftOperation(extension),
 795         0xc3 => .ret,
 796         0xcd => .int_,
 797         0xe8 => .call,
 798         0xe9, 0xeb => .jmp,
 799         0xee => .out,
 800         0xf4 => .hlt,
 801         0xf5 => .cmc,
 802         0xf6 => groupThreeByteOperation(extension),
 803         0xf7 => groupThreeOperation(extension),
 804         0xfa => .cli,
 805         0xfb => .sti,
 806         0xfe => groupFourOperation(extension),
 807         0xff => groupFiveOperation(extension),
 808         else => null,
 809     };
 810 }
 811 
 812 fn arithmeticOperation(opcode: u8) ?x86.Operation {
 813     return switch (opcode & 0xf8) {
 814         0x00 => if (opcode <= 0x05) .add else null,
 815         0x08 => if (opcode <= 0x0d) .or_ else null,
 816         0x18 => if (opcode <= 0x1d) .sbb else null,
 817         0x20 => if (opcode <= 0x25) .and_ else null,
 818         0x28 => if (opcode <= 0x2d) .sub else null,
 819         0x30 => if (opcode <= 0x35) .xor_ else null,
 820         0x38 => if (opcode == 0x38 or opcode == 0x39 or
 821             (opcode >= 0x3b and opcode <= 0x3d)) .cmp else null,
 822         else => null,
 823     };
 824 }
 825 
 826 fn groupOneOperation(extension: ?u3) ?x86.Operation {
 827     return switch (extension orelse return null) {
 828         0 => .add,
 829         1 => .or_,
 830         2 => .adc,
 831         3 => .sbb,
 832         4 => .and_,
 833         5 => .sub,
 834         6 => .xor_,
 835         7 => .cmp,
 836     };
 837 }
 838 
 839 fn shiftOperation(extension: ?u3) ?x86.Operation {
 840     return switch (extension orelse return null) {
 841         0 => .rol,
 842         1 => .ror,
 843         4, 6 => .shl,
 844         5 => .shr,
 845         7 => .sar,
 846         else => null,
 847     };
 848 }
 849 
 850 fn groupThreeOperation(extension: ?u3) ?x86.Operation {
 851     return switch (extension orelse return null) {
 852         0 => .test_,
 853         2 => .not_,
 854         3 => .neg,
 855         4 => .mul,
 856         5 => .imul,
 857         6 => .div,
 858         7 => .idiv,
 859         else => null,
 860     };
 861 }
 862 
 863 fn groupThreeByteOperation(extension: ?u3) ?x86.Operation {
 864     return switch (extension orelse return null) {
 865         0 => .test_,
 866         2 => .not_,
 867         3 => .neg,
 868         else => null,
 869     };
 870 }
 871 
 872 fn groupFiveOperation(extension: ?u3) ?x86.Operation {
 873     return switch (extension orelse return null) {
 874         0 => .inc,
 875         1 => .dec,
 876         2 => .call,
 877         4 => .jmp,
 878         else => null,
 879     };
 880 }
 881 
 882 fn groupFourOperation(extension: ?u3) ?x86.Operation {
 883     return switch (extension orelse return null) {
 884         0 => .inc,
 885         1 => .dec,
 886         else => null,
 887     };
 888 }
 889 
 890 fn operationTwo(
 891     prefix: PrefixState,
 892     opcode: u8,
 893     extension: ?u3,
 894 ) ?x86.Operation {
 895     if ((opcode >= 0x82 and opcode <= 0x87) or
 896         (opcode >= 0x8c and opcode <= 0x8f)) return conditionOperation(opcode & 0x0f);
 897     if (opcode >= 0xc8 and opcode <= 0xcf) {
 898         return if (bareOrRex(prefix.form)) .bswap else null;
 899     }
 900     return switch (opcode) {
 901         0x0b => .ud2,
 902         0x10, 0x11 => if (bareOrRex(prefix.form)) .movups else null,
 903         0x1f => if (extension == 0) .nop else null,
 904         0x30 => .wrmsr,
 905         0x32 => .rdmsr,
 906         0x42 => .cmovb,
 907         0x43 => .cmovae,
 908         0x44 => .cmove,
 909         0x45 => .cmovne,
 910         0x47 => .cmova,
 911         0x6f, 0x7f => if (prefix.form.repeated()) .movdqu else null,
 912         0x70 => if (operand16Encoding(prefix.form)) .pshufd else null,
 913         0x90 => if (extension == 0 and bareOrRex(prefix.form)) .seto else null,
 914         0x92 => if (extension == 0 and bareOrRex(prefix.form)) .setb else null,
 915         0x93 => if (extension == 0 and bareOrRex(prefix.form)) .setae else null,
 916         0x94 => if (extension == 0 and bareOrRex(prefix.form)) .sete else null,
 917         0x95 => if (extension == 0 and bareOrRex(prefix.form)) .setne else null,
 918         0x96 => if (extension == 0 and bareOrRex(prefix.form)) .setbe else null,
 919         0x97 => if (extension == 0 and bareOrRex(prefix.form)) .seta else null,
 920         0x9c => if (extension == 0 and bareOrRex(prefix.form)) .setl else null,
 921         0x9d => if (extension == 0 and bareOrRex(prefix.form)) .setge else null,
 922         0x9e => if (extension == 0 and bareOrRex(prefix.form)) .setle else null,
 923         0x9f => if (extension == 0 and bareOrRex(prefix.form)) .setg else null,
 924         0xa2 => .cpuid,
 925         0xaf => .imul,
 926         0xb0 => .cmpxchg,
 927         0xb6, 0xb7 => .movzx,
 928         0xbe, 0xbf => .movsx,
 929         else => null,
 930     };
 931 }
 932 
 933 fn bareOrRex(prefix: x86.Prefix) bool {
 934     return prefix == .none or
 935         (prefix.rexByte() != 0 and prefix.bytes().len == 1);
 936 }
 937 
 938 fn operand16Encoding(prefix: x86.Prefix) bool {
 939     return switch (prefix) {
 940         .operand16,
 941         .operand16_rex_b,
 942         .operand16_rex_r,
 943         .operand16_rex_rb,
 944         => true,
 945         else => false,
 946     };
 947 }
 948 
 949 fn conditionOperation(code: u8) ?x86.Operation {
 950     return switch (code) {
 951         0x2 => .jb,
 952         0x3 => .jae,
 953         0x4 => .je,
 954         0x5 => .jne,
 955         0x6 => .jbe,
 956         0x7 => .ja,
 957         0xc => .jl,
 958         0xd => .jge,
 959         0xe => .jle,
 960         0xf => .jg,
 961         else => null,
 962     };
 963 }
 964 
 965 fn parsePayload(
 966     code: []const u8,
 967     cursor: *usize,
 968     prefix: PrefixState,
 969     map: x86.Map,
 970     opcode: u8,
 971     modrm: ?ModRm,
 972 ) Error!Payload {
 973     return switch (map) {
 974         .one => parseOnePayload(code, cursor, prefix, opcode, modrm),
 975         .two => parseTwoPayload(code, cursor, opcode),
 976     };
 977 }
 978 
 979 fn parseOnePayload(
 980     code: []const u8,
 981     cursor: *usize,
 982     prefix: PrefixState,
 983     opcode: u8,
 984     modrm: ?ModRm,
 985 ) Error!Payload {
 986     if (arithmeticImmediateBytes(prefix, opcode)) |bytes| {
 987         return immediatePayload(code, cursor, bytes, prefix.wide());
 988     }
 989     if ((opcode >= 0x72 and opcode <= 0x77) or
 990         (opcode >= 0x7c and opcode <= 0x7f)) return relativePayload(code, cursor, 1);
 991     if (opcode >= 0xb0 and opcode <= 0xb7) return immediatePayload(code, cursor, 1, false);
 992     if (opcode >= 0xb8 and opcode <= 0xbf) {
 993         const bytes = if (prefix.wide()) 8 else operandBytes(prefix);
 994         return immediatePayload(code, cursor, bytes, false);
 995     }
 996     return switch (opcode) {
 997         0x69 => immediatePayload(code, cursor, operandBytes(prefix), prefix.wide()),
 998         0x6a, 0x6b, 0x80, 0x83 => immediatePayload(code, cursor, 1, opcode != 0x80),
 999         0x81 => immediatePayload(code, cursor, operandBytes(prefix), prefix.wide()),
1000         0xa8 => immediatePayload(code, cursor, 1, false),
1001         0xa9 => immediatePayload(code, cursor, operandBytes(prefix), prefix.wide()),
1002         0xc0, 0xc1 => immediatePayload(code, cursor, 1, false),
1003         0xc6 => immediatePayload(code, cursor, 1, false),
1004         0xc7 => immediatePayload(code, cursor, operandBytes(prefix), prefix.wide()),
1005         0xcd => immediatePayload(code, cursor, 1, false),
1006         0xe8, 0xe9 => relativePayload(code, cursor, 4),
1007         0xeb => relativePayload(code, cursor, 1),
1008         0xf6, 0xf7 => if (modrm.?.extension == 0)
1009             immediatePayload(
1010                 code,
1011                 cursor,
1012                 if (opcode == 0xf6) 1 else operandBytes(prefix),
1013                 opcode == 0xf7 and prefix.wide(),
1014             )
1015         else
1016             .{},
1017         else => .{},
1018     };
1019 }
1020 
1021 fn parseTwoPayload(
1022     code: []const u8,
1023     cursor: *usize,
1024     opcode: u8,
1025 ) Error!Payload {
1026     if ((opcode >= 0x82 and opcode <= 0x87) or
1027         (opcode >= 0x8c and opcode <= 0x8f)) return relativePayload(code, cursor, 4);
1028     if (opcode == 0x70) return immediatePayload(code, cursor, 1, false);
1029     return .{};
1030 }
1031 
1032 fn arithmeticImmediateBytes(prefix: PrefixState, opcode: u8) ?usize {
1033     const form = opcode & 7;
1034     if (arithmeticOperation(opcode) == null) return null;
1035     if (form == 4) return 1;
1036     if (form == 5) return operandBytes(prefix);
1037     return null;
1038 }
1039 
1040 fn operandBytes(prefix: PrefixState) usize {
1041     return if (!prefix.wide() and prefix.form.hasOperand16()) 2 else 4;
1042 }
1043 
1044 fn immediatePayload(
1045     code: []const u8,
1046     cursor: *usize,
1047     bytes: usize,
1048     sign: bool,
1049 ) Error!Payload {
1050     return .{ .immediate = .{
1051         .value = try readUnsigned(code, cursor, bytes),
1052         .encoded_bytes = @intCast(bytes),
1053         .extension = if (sign) .sign else .none,
1054     } };
1055 }
1056 
1057 fn relativePayload(code: []const u8, cursor: *usize, bytes: usize) Error!Payload {
1058     return .{ .relative = switch (bytes) {
1059         1 => try readI8(code, cursor),
1060         4 => try readI32(code, cursor),
1061         else => unreachable,
1062     } };
1063 }
1064 
1065 fn createInstruction(
1066     form: x86.Form,
1067     operation: x86.Operation,
1068     bytes: usize,
1069     prefix: PrefixState,
1070     modrm: ?ModRm,
1071     payload: Payload,
1072 ) x86.Instruction {
1073     const shape_value = shape(form.map, form.opcode, if (modrm) |value| value.extension else null);
1074     var result = x86.Instruction{
1075         .form = form,
1076         .operation = operation,
1077         .family = operation.family(),
1078         .bytes = @intCast(bytes),
1079         .register_access = shape_value.register_access,
1080         .operand_access = shape_value.operand_access,
1081         .embedded_access = shape_value.embedded_access,
1082         .immediate = payload.immediate,
1083         .relative = payload.relative,
1084     };
1085     if (modrm) |value| applyDecodedOperands(&result, prefix, shape_value, value);
1086     if (modrm) |value| {
1087         result.modrm_mode = value.mode_raw;
1088         result.modrm_operand = value.operand;
1089     }
1090     result.embedded = decodedEmbedded(form, prefix, shape_value);
1091     applyExactEncoding(&result, prefix);
1092     return result;
1093 }
1094 
1095 fn applyExactEncoding(result: *x86.Instruction, prefix: PrefixState) void {
1096     switch (result.operation) {
1097         .bswap => result.embedded_access = .read_write,
1098         .xchg => if (result.form.map == .one and result.form.opcode == 0x90) {
1099             const width = if (prefix.form.hasOperand16())
1100                 x86.Width.word
1101             else if (prefix.wide())
1102                 x86.Width.qword
1103             else
1104                 x86.Width.dword;
1105             result.register = gprRegister(0, width, prefix, false);
1106             result.register_access = .read_write;
1107             result.embedded = gprRegister(prefix.rexB(), width, prefix, false);
1108             result.embedded_access = .read_write;
1109         },
1110         else => {},
1111     }
1112 }
1113 
1114 fn applyDecodedOperands(
1115     result: *x86.Instruction,
1116     prefix: PrefixState,
1117     shape_value: Shape,
1118     modrm: ModRm,
1119 ) void {
1120     if (shape_value.register_bank == .gpr) {
1121         result.register = gprRegister(
1122             modrm.register,
1123             result.form.width,
1124             prefix,
1125             shape_value.register_high8,
1126         );
1127     } else if (shape_value.register_bank == .vector) {
1128         result.register = vectorRegister(modrm.register);
1129     }
1130     if (modrm.mode == .register) {
1131         result.operand = decodedRegisterOperand(result.form, prefix, shape_value, modrm);
1132     } else {
1133         result.operand = .{ .memory = decodedMemory(
1134             result.form,
1135             shape_value,
1136             modrm,
1137         ) };
1138     }
1139 }
1140 
1141 fn decodedRegisterOperand(
1142     form: x86.Form,
1143     prefix: PrefixState,
1144     shape_value: Shape,
1145     modrm: ModRm,
1146 ) x86.Operand {
1147     if (shape_value.operand_bank == .vector) {
1148         return .{ .register = vectorRegister(modrm.operand) };
1149     }
1150     const width = operandWidthFor(form, shape_value);
1151     return .{ .register = gprRegister(
1152         modrm.operand,
1153         width,
1154         prefix,
1155         shape_value.operand_high8,
1156     ) };
1157 }
1158 
1159 fn decodedMemory(
1160     form: x86.Form,
1161     shape_value: Shape,
1162     modrm: ModRm,
1163 ) x86.Memory {
1164     return .{
1165         .kind = modrm.address,
1166         .width = if (shape_value.operand_access == .none)
1167             .none
1168         else
1169             operandWidthFor(form, shape_value),
1170         .base = if (modrm.base) |number| addressRegister(number) else null,
1171         .index = if (modrm.index) |number| addressRegister(number) else null,
1172         .scale = modrm.scale,
1173         .displacement = modrm.displacement,
1174         .segment = modrm.segment,
1175     };
1176 }
1177 
1178 fn decodedEmbedded(
1179     form: x86.Form,
1180     prefix: PrefixState,
1181     shape_value: Shape,
1182 ) ?x86.Register {
1183     return switch (shape_value.embedded) {
1184         .none => null,
1185         .accumulator => gprRegister(0, form.width, prefix, form.width == .byte),
1186         .opcode => gprRegister(
1187             @as(u4, @intCast(form.opcode & 7)) | prefix.rexB(),
1188             form.width,
1189             prefix,
1190             form.width == .byte,
1191         ),
1192     };
1193 }
1194 
1195 fn gprRegister(
1196     number: u4,
1197     width: x86.Width,
1198     prefix: PrefixState,
1199     high8: bool,
1200 ) x86.Register {
1201     if (high8 and prefix.rex == 0 and number >= 4 and number <= 7) {
1202         return .{ .number = number - 4, .lane = .high8 };
1203     }
1204     return .{ .number = number, .lane = laneFor(width) };
1205 }
1206 
1207 fn vectorRegister(number: u4) x86.Register {
1208     return .{ .bank = .vector, .number = number, .lane = .vector128 };
1209 }
1210 
1211 fn addressRegister(number: u4) x86.Register {
1212     return .{ .number = number, .lane = .qword };
1213 }
1214 
1215 fn laneFor(width: x86.Width) x86.RegisterLane {
1216     return switch (width) {
1217         .byte => .low8,
1218         .word => .word,
1219         .dword => .dword,
1220         .qword, .none => .qword,
1221         .vector128 => .vector128,
1222     };
1223 }
1224 
1225 fn addImplicitOperands(result: *x86.Instruction, prefix: PrefixState) void {
1226     switch (result.operation) {
1227         .push, .pop, .pushf, .call, .ret => addImplicit(result, gprUse(4, .qword, .read_write)),
1228         .mul, .div, .idiv => addMultiplyImplicit(result),
1229         .imul => if (result.form.opcode == 0xf6 or result.form.opcode == 0xf7)
1230             addMultiplyImplicit(result),
1231         .out => {
1232             addImplicit(result, gprUse(2, .word, .read));
1233             addImplicit(result, gprUse(0, .low8, .read));
1234         },
1235         .movs => addStringImplicit(result, prefix, false),
1236         .stos => addStringImplicit(result, prefix, true),
1237         .cmpxchg => addImplicit(result, gprUse(0, .low8, .read_write)),
1238         .cpuid => addCpuidImplicit(result),
1239         .rdmsr => addRdmsrImplicit(result),
1240         .wrmsr => addWrmsrImplicit(result),
1241         .rol, .ror, .sar, .shl, .shr => if (result.form.opcode == 0xd2 or
1242             result.form.opcode == 0xd3) addImplicit(result, gprUse(1, .low8, .read)),
1243         else => {},
1244     }
1245 }
1246 
1247 fn addMultiplyImplicit(result: *x86.Instruction) void {
1248     const lane = laneFor(result.form.width);
1249     addImplicit(result, gprUse(0, lane, .read_write));
1250     addImplicit(result, gprUse(
1251         2,
1252         lane,
1253         if (result.operation == .mul or result.operation == .imul)
1254             .write
1255         else
1256             .read_write,
1257     ));
1258 }
1259 
1260 fn addStringImplicit(
1261     result: *x86.Instruction,
1262     prefix: PrefixState,
1263     accumulator: bool,
1264 ) void {
1265     if (!accumulator) addImplicit(result, gprUse(6, .qword, .read_write));
1266     if (accumulator) {
1267         addImplicit(result, gprUse(0, laneFor(result.form.width), .read));
1268     }
1269     addImplicit(result, gprUse(7, .qword, .read_write));
1270     if (prefix.form.repeated()) addImplicit(result, gprUse(1, .qword, .read_write));
1271 }
1272 
1273 fn addCpuidImplicit(result: *x86.Instruction) void {
1274     addImplicit(result, gprUse(0, .dword, .read_write));
1275     addImplicit(result, gprUse(1, .dword, .read_write));
1276     addImplicit(result, gprUse(2, .dword, .write));
1277     addImplicit(result, gprUse(3, .dword, .write));
1278 }
1279 
1280 fn addRdmsrImplicit(result: *x86.Instruction) void {
1281     addImplicit(result, gprUse(1, .dword, .read));
1282     addImplicit(result, gprUse(0, .dword, .write));
1283     addImplicit(result, gprUse(2, .dword, .write));
1284 }
1285 
1286 fn addWrmsrImplicit(result: *x86.Instruction) void {
1287     addImplicit(result, gprUse(1, .dword, .read));
1288     addImplicit(result, gprUse(0, .dword, .read));
1289     addImplicit(result, gprUse(2, .dword, .read));
1290 }
1291 
1292 fn gprUse(number: u4, lane: x86.RegisterLane, access: x86.Access) x86.RegisterAccess {
1293     return .{ .register = .{ .number = number, .lane = lane }, .access = access };
1294 }
1295 
1296 fn addImplicit(result: *x86.Instruction, value: x86.RegisterAccess) void {
1297     std.debug.assert(result.implicit_count < result.implicit.len);
1298     result.implicit[result.implicit_count] = value;
1299     result.implicit_count += 1;
1300 }
1301 
1302 fn modeFromRaw(value: u2) x86.Mode {
1303     return switch (value) {
1304         0 => .memory,
1305         1 => .displacement8,
1306         2 => .displacement32,
1307         3 => .register,
1308     };
1309 }
1310 
1311 fn readI8(code: []const u8, cursor: *usize) Error!i32 {
1312     return @as(i8, @bitCast(try takeByte(code, cursor)));
1313 }
1314 
1315 fn readI32(code: []const u8, cursor: *usize) Error!i32 {
1316     const value = try take(code, cursor, 4);
1317     return std.mem.readInt(i32, value[0..4], .little);
1318 }
1319 
1320 fn readUnsigned(code: []const u8, cursor: *usize, bytes: usize) Error!u64 {
1321     const value = try take(code, cursor, bytes);
1322     return switch (bytes) {
1323         1 => value[0],
1324         2 => std.mem.readInt(u16, value[0..2], .little),
1325         4 => std.mem.readInt(u32, value[0..4], .little),
1326         8 => std.mem.readInt(u64, value[0..8], .little),
1327         else => error.InvalidEncoding,
1328     };
1329 }
1330 
1331 fn takeByte(code: []const u8, cursor: *usize) Error!u8 {
1332     return (try take(code, cursor, 1))[0];
1333 }
1334 
1335 fn take(code: []const u8, cursor: *usize, count: usize) Error![]const u8 {
1336     if (cursor.* > code.len or count > code.len - cursor.*) {
1337         return error.TruncatedInstruction;
1338     }
1339     if (cursor.* + count > 15) return error.InstructionTooLong;
1340     const result = code[cursor.*..][0..count];
1341     cursor.* += count;
1342     return result;
1343 }