| ... | @@ -183,11 +183,14 @@ pub fn lowerMir(emit: *Emit) InnerError!void { | ... | @@ -183,11 +183,14 @@ pub fn lowerMir(emit: *Emit) InnerError!void { |
| 183 | .nop => try emit.mirNop(), | 183 | .nop => try emit.mirNop(), |
| 184 | | 184 | |
| 185 | // AVX instructions | 185 | // AVX instructions |
| 186 | .mov_f64 => try emit.mirMovF64(inst), | 186 | .mov_f64 => try emit.mirMovFloatAvx(.vmovsd, inst), |
| | 187 | .mov_f32 => try emit.mirMovFloatAvx(.vmovss, inst), |
| 187 | | 188 | |
| 188 | .add_f64 => try emit.mirAddF64(inst), | 189 | .add_f64 => try emit.mirAddFloatAvx(.vaddsd, inst), |
| | 190 | .add_f32 => try emit.mirAddFloatAvx(.vaddss, inst), |
| 189 | | 191 | |
| 190 | .cmp_f64 => try emit.mirCmpF64(inst), | 192 | .cmp_f64 => try emit.mirCmpFloatAvx(.vucomisd, inst), |
| | 193 | .cmp_f32 => try emit.mirCmpFloatAvx(.vucomiss, inst), |
| 191 | | 194 | |
| 192 | // Pseudo-instructions | 195 | // Pseudo-instructions |
| 193 | .call_extern => try emit.mirCallExtern(inst), | 196 | .call_extern => try emit.mirCallExtern(inst), |
| ... | @@ -962,71 +965,48 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -962,71 +965,48 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 962 | | 965 | |
| 963 | // AVX instructions | 966 | // AVX instructions |
| 964 | | 967 | |
| 965 | fn mirMovF64(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | 968 | fn mirMovFloatAvx(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 966 | const tag = emit.mir.instructions.items(.tag)[inst]; | | |
| 967 | assert(tag == .mov_f64); | | |
| 968 | const ops = emit.mir.instructions.items(.ops)[inst].decode(); | 969 | const ops = emit.mir.instructions.items(.ops)[inst].decode(); |
| 969 | | 970 | |
| 970 | switch (ops.flags) { | 971 | switch (ops.flags) { |
| 971 | 0b00 => { | 972 | 0b00 => { |
| 972 | const imm = emit.mir.instructions.items(.data)[inst].imm; | 973 | const imm = emit.mir.instructions.items(.data)[inst].imm; |
| 973 | return lowerToVmEnc(.vmovsd, ops.reg1, RegisterOrMemory.mem(.qword_ptr, .{ | 974 | return lowerToVmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.new(ops.reg2.size()), .{ |
| 974 | .disp = imm, | 975 | .disp = imm, |
| 975 | .base = ops.reg2, | 976 | .base = ops.reg2, |
| 976 | }), emit.code); | 977 | }), emit.code); |
| 977 | }, | 978 | }, |
| 978 | 0b01 => { | 979 | 0b01 => { |
| 979 | const imm = emit.mir.instructions.items(.data)[inst].imm; | 980 | const imm = emit.mir.instructions.items(.data)[inst].imm; |
| 980 | return lowerToMvEnc(.vmovsd, RegisterOrMemory.mem(.qword_ptr, .{ | 981 | return lowerToMvEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.new(ops.reg1.size()), .{ |
| 981 | .disp = imm, | 982 | .disp = imm, |
| 982 | .base = ops.reg1, | 983 | .base = ops.reg1, |
| 983 | }), ops.reg2, emit.code); | 984 | }), ops.reg2, emit.code); |
| 984 | }, | 985 | }, |
| 985 | 0b10 => { | 986 | 0b10 => { |
| 986 | return lowerToRvmEnc( | 987 | return lowerToRvmEnc(tag, ops.reg1, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code); |
| 987 | .vmovsd, | | |
| 988 | ops.reg1, | | |
| 989 | ops.reg1, | | |
| 990 | RegisterOrMemory.reg(ops.reg2), | | |
| 991 | emit.code, | | |
| 992 | ); | | |
| 993 | }, | 988 | }, |
| 994 | else => return emit.fail("TODO unused variant 0b{b} for mov_f64", .{ops.flags}), | 989 | else => return emit.fail("TODO unused variant 0b{b} for mov_f64", .{ops.flags}), |
| 995 | } | 990 | } |
| 996 | } | 991 | } |
| 997 | | 992 | |
| 998 | fn mirAddF64(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | 993 | fn mirAddFloatAvx(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 999 | const tag = emit.mir.instructions.items(.tag)[inst]; | | |
| 1000 | assert(tag == .add_f64); | | |
| 1001 | const ops = emit.mir.instructions.items(.ops)[inst].decode(); | 994 | const ops = emit.mir.instructions.items(.ops)[inst].decode(); |
| 1002 | | 995 | |
| 1003 | switch (ops.flags) { | 996 | switch (ops.flags) { |
| 1004 | 0b00 => { | 997 | 0b00 => { |
| 1005 | return lowerToRvmEnc( | 998 | return lowerToRvmEnc(tag, ops.reg1, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code); |
| 1006 | .vaddsd, | | |
| 1007 | ops.reg1, | | |
| 1008 | ops.reg1, | | |
| 1009 | RegisterOrMemory.reg(ops.reg2), | | |
| 1010 | emit.code, | | |
| 1011 | ); | | |
| 1012 | }, | 999 | }, |
| 1013 | else => return emit.fail("TODO unused variant 0b{b} for mov_f64", .{ops.flags}), | 1000 | else => return emit.fail("TODO unused variant 0b{b} for mov_f64", .{ops.flags}), |
| 1014 | } | 1001 | } |
| 1015 | } | 1002 | } |
| 1016 | | 1003 | |
| 1017 | fn mirCmpF64(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | 1004 | fn mirCmpFloatAvx(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 1018 | const tag = emit.mir.instructions.items(.tag)[inst]; | | |
| 1019 | assert(tag == .cmp_f64); | | |
| 1020 | const ops = emit.mir.instructions.items(.ops)[inst].decode(); | 1005 | const ops = emit.mir.instructions.items(.ops)[inst].decode(); |
| 1021 | | 1006 | |
| 1022 | switch (ops.flags) { | 1007 | switch (ops.flags) { |
| 1023 | 0b00 => { | 1008 | 0b00 => { |
| 1024 | return lowerToVmEnc( | 1009 | return lowerToVmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code); |
| 1025 | .vucomisd, | | |
| 1026 | ops.reg1, | | |
| 1027 | RegisterOrMemory.reg(ops.reg2), | | |
| 1028 | emit.code, | | |
| 1029 | ); | | |
| 1030 | }, | 1010 | }, |
| 1031 | else => return emit.fail("TODO unused variant 0b{b} for mov_f64", .{ops.flags}), | 1011 | else => return emit.fail("TODO unused variant 0b{b} for mov_f64", .{ops.flags}), |
| 1032 | } | 1012 | } |
| ... | @@ -1268,16 +1248,24 @@ const Tag = enum { | ... | @@ -1268,16 +1248,24 @@ const Tag = enum { |
| 1268 | cmovb, | 1248 | cmovb, |
| 1269 | cmovnae, | 1249 | cmovnae, |
| 1270 | vmovsd, | 1250 | vmovsd, |
| | 1251 | vmovss, |
| 1271 | vaddsd, | 1252 | vaddsd, |
| | 1253 | vaddss, |
| 1272 | vcmpsd, | 1254 | vcmpsd, |
| | 1255 | vcmpss, |
| 1273 | vucomisd, | 1256 | vucomisd, |
| | 1257 | vucomiss, |
| 1274 | | 1258 | |
| 1275 | fn isAvx(tag: Tag) bool { | 1259 | fn isAvx(tag: Tag) bool { |
| 1276 | return switch (tag) { | 1260 | return switch (tag) { |
| 1277 | .vmovsd, | 1261 | .vmovsd, |
| | 1262 | .vmovss, |
| 1278 | .vaddsd, | 1263 | .vaddsd, |
| | 1264 | .vaddss, |
| 1279 | .vcmpsd, | 1265 | .vcmpsd, |
| | 1266 | .vcmpss, |
| 1280 | .vucomisd, | 1267 | .vucomisd, |
| | 1268 | .vucomiss, |
| 1281 | => true, | 1269 | => true, |
| 1282 | | 1270 | |
| 1283 | else => false, | 1271 | else => false, |
| ... | @@ -1406,7 +1394,7 @@ const OpCode = union(enum) { | ... | @@ -1406,7 +1394,7 @@ const OpCode = union(enum) { |
| 1406 | } | 1394 | } |
| 1407 | }; | 1395 | }; |
| 1408 | | 1396 | |
| 1409 | inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode { | 1397 | inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) OpCode { |
| 1410 | switch (enc) { | 1398 | switch (enc) { |
| 1411 | .zo => return switch (tag) { | 1399 | .zo => return switch (tag) { |
| 1412 | .ret_near => OpCode.oneByte(0xc3), | 1400 | .ret_near => OpCode.oneByte(0xc3), |
| ... | @@ -1416,7 +1404,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode { | ... | @@ -1416,7 +1404,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode { |
| 1416 | .syscall => OpCode.twoByte(0x0f, 0x05), | 1404 | .syscall => OpCode.twoByte(0x0f, 0x05), |
| 1417 | .cbw => OpCode.oneByte(0x98), | 1405 | .cbw => OpCode.oneByte(0x98), |
| 1418 | .cwd, .cdq, .cqo => OpCode.oneByte(0x99), | 1406 | .cwd, .cdq, .cqo => OpCode.oneByte(0x99), |
| 1419 | else => null, | 1407 | else => unreachable, |
| 1420 | }, | 1408 | }, |
| 1421 | .d => return switch (tag) { | 1409 | .d => return switch (tag) { |
| 1422 | .jmp_near => OpCode.oneByte(0xe9), | 1410 | .jmp_near => OpCode.oneByte(0xe9), |
| ... | @@ -1437,7 +1425,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode { | ... | @@ -1437,7 +1425,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode { |
| 1437 | .jge, .jnl => if (is_one_byte) OpCode.oneByte(0x7d) else OpCode.twoByte(0x0f, 0x8d), | 1425 | .jge, .jnl => if (is_one_byte) OpCode.oneByte(0x7d) else OpCode.twoByte(0x0f, 0x8d), |
| 1438 | .jle, .jng => if (is_one_byte) OpCode.oneByte(0x7e) else OpCode.twoByte(0x0f, 0x8e), | 1426 | .jle, .jng => if (is_one_byte) OpCode.oneByte(0x7e) else OpCode.twoByte(0x0f, 0x8e), |
| 1439 | .jg, .jnle => if (is_one_byte) OpCode.oneByte(0x7f) else OpCode.twoByte(0x0f, 0x8f), | 1427 | .jg, .jnle => if (is_one_byte) OpCode.oneByte(0x7f) else OpCode.twoByte(0x0f, 0x8f), |
| 1440 | else => null, | 1428 | else => unreachable, |
| 1441 | }, | 1429 | }, |
| 1442 | .m => return switch (tag) { | 1430 | .m => return switch (tag) { |
| 1443 | .jmp_near, .call_near, .push => OpCode.oneByte(0xff), | 1431 | .jmp_near, .call_near, .push => OpCode.oneByte(0xff), |
| ... | @@ -1464,38 +1452,38 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode { | ... | @@ -1464,38 +1452,38 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode { |
| 1464 | .fisttp64 => OpCode.oneByte(0xdd), | 1452 | .fisttp64 => OpCode.oneByte(0xdd), |
| 1465 | .fld32 => OpCode.oneByte(0xd9), | 1453 | .fld32 => OpCode.oneByte(0xd9), |
| 1466 | .fld64 => OpCode.oneByte(0xdd), | 1454 | .fld64 => OpCode.oneByte(0xdd), |
| 1467 | else => null, | 1455 | else => unreachable, |
| 1468 | }, | 1456 | }, |
| 1469 | .o => return switch (tag) { | 1457 | .o => return switch (tag) { |
| 1470 | .push => OpCode.oneByte(0x50), | 1458 | .push => OpCode.oneByte(0x50), |
| 1471 | .pop => OpCode.oneByte(0x58), | 1459 | .pop => OpCode.oneByte(0x58), |
| 1472 | else => null, | 1460 | else => unreachable, |
| 1473 | }, | 1461 | }, |
| 1474 | .i => return switch (tag) { | 1462 | .i => return switch (tag) { |
| 1475 | .push => OpCode.oneByte(if (is_one_byte) 0x6a else 0x68), | 1463 | .push => OpCode.oneByte(if (is_one_byte) 0x6a else 0x68), |
| 1476 | .@"test" => OpCode.oneByte(if (is_one_byte) 0xa8 else 0xa9), | 1464 | .@"test" => OpCode.oneByte(if (is_one_byte) 0xa8 else 0xa9), |
| 1477 | .ret_near => OpCode.oneByte(0xc2), | 1465 | .ret_near => OpCode.oneByte(0xc2), |
| 1478 | .ret_far => OpCode.oneByte(0xca), | 1466 | .ret_far => OpCode.oneByte(0xca), |
| 1479 | else => null, | 1467 | else => unreachable, |
| 1480 | }, | 1468 | }, |
| 1481 | .m1 => return switch (tag) { | 1469 | .m1 => return switch (tag) { |
| 1482 | .shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xd0 else 0xd1), | 1470 | .shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xd0 else 0xd1), |
| 1483 | else => null, | 1471 | else => unreachable, |
| 1484 | }, | 1472 | }, |
| 1485 | .mc => return switch (tag) { | 1473 | .mc => return switch (tag) { |
| 1486 | .shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xd2 else 0xd3), | 1474 | .shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xd2 else 0xd3), |
| 1487 | else => null, | 1475 | else => unreachable, |
| 1488 | }, | 1476 | }, |
| 1489 | .mi => return switch (tag) { | 1477 | .mi => return switch (tag) { |
| 1490 | .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => OpCode.oneByte(if (is_one_byte) 0x80 else 0x81), | 1478 | .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => OpCode.oneByte(if (is_one_byte) 0x80 else 0x81), |
| 1491 | .mov => OpCode.oneByte(if (is_one_byte) 0xc6 else 0xc7), | 1479 | .mov => OpCode.oneByte(if (is_one_byte) 0xc6 else 0xc7), |
| 1492 | .@"test" => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7), | 1480 | .@"test" => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7), |
| 1493 | else => null, | 1481 | else => unreachable, |
| 1494 | }, | 1482 | }, |
| 1495 | .mi8 => return switch (tag) { | 1483 | .mi8 => return switch (tag) { |
| 1496 | .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => OpCode.oneByte(0x83), | 1484 | .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => OpCode.oneByte(0x83), |
| 1497 | .shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xc0 else 0xc1), | 1485 | .shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xc0 else 0xc1), |
| 1498 | else => null, | 1486 | else => unreachable, |
| 1499 | }, | 1487 | }, |
| 1500 | .mr => return switch (tag) { | 1488 | .mr => return switch (tag) { |
| 1501 | .adc => OpCode.oneByte(if (is_one_byte) 0x10 else 0x11), | 1489 | .adc => OpCode.oneByte(if (is_one_byte) 0x10 else 0x11), |
| ... | @@ -1508,8 +1496,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode { | ... | @@ -1508,8 +1496,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode { |
| 1508 | .cmp => OpCode.oneByte(if (is_one_byte) 0x38 else 0x39), | 1496 | .cmp => OpCode.oneByte(if (is_one_byte) 0x38 else 0x39), |
| 1509 | .mov => OpCode.oneByte(if (is_one_byte) 0x88 else 0x89), | 1497 | .mov => OpCode.oneByte(if (is_one_byte) 0x88 else 0x89), |
| 1510 | .@"test" => OpCode.oneByte(if (is_one_byte) 0x84 else 0x85), | 1498 | .@"test" => OpCode.oneByte(if (is_one_byte) 0x84 else 0x85), |
| 1511 | .vmovsd => OpCode.oneByte(0x11), | 1499 | else => unreachable, |
| 1512 | else => null, | | |
| 1513 | }, | 1500 | }, |
| 1514 | .rm => return switch (tag) { | 1501 | .rm => return switch (tag) { |
| 1515 | .adc => OpCode.oneByte(if (is_one_byte) 0x12 else 0x13), | 1502 | .adc => OpCode.oneByte(if (is_one_byte) 0x12 else 0x13), |
| ... | @@ -1529,48 +1516,46 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode { | ... | @@ -1529,48 +1516,46 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode { |
| 1529 | .cmove, .cmovz => OpCode.twoByte(0x0f, 0x44), | 1516 | .cmove, .cmovz => OpCode.twoByte(0x0f, 0x44), |
| 1530 | .cmovb, .cmovnae => OpCode.twoByte(0x0f, 0x42), | 1517 | .cmovb, .cmovnae => OpCode.twoByte(0x0f, 0x42), |
| 1531 | .cmovl, .cmovng => OpCode.twoByte(0x0f, 0x4c), | 1518 | .cmovl, .cmovng => OpCode.twoByte(0x0f, 0x4c), |
| 1532 | .vmovsd => OpCode.oneByte(0x10), | 1519 | else => unreachable, |
| 1533 | .vucomisd => OpCode.oneByte(0x2e), | | |
| 1534 | else => null, | | |
| 1535 | }, | 1520 | }, |
| 1536 | .oi => return switch (tag) { | 1521 | .oi => return switch (tag) { |
| 1537 | .mov => OpCode.oneByte(if (is_one_byte) 0xb0 else 0xb8), | 1522 | .mov => OpCode.oneByte(if (is_one_byte) 0xb0 else 0xb8), |
| 1538 | else => null, | 1523 | else => unreachable, |
| 1539 | }, | 1524 | }, |
| 1540 | .fd => return switch (tag) { | 1525 | .fd => return switch (tag) { |
| 1541 | .mov => OpCode.oneByte(if (is_one_byte) 0xa0 else 0xa1), | 1526 | .mov => OpCode.oneByte(if (is_one_byte) 0xa0 else 0xa1), |
| 1542 | else => null, | 1527 | else => unreachable, |
| 1543 | }, | 1528 | }, |
| 1544 | .td => return switch (tag) { | 1529 | .td => return switch (tag) { |
| 1545 | .mov => OpCode.oneByte(if (is_one_byte) 0xa2 else 0xa3), | 1530 | .mov => OpCode.oneByte(if (is_one_byte) 0xa2 else 0xa3), |
| 1546 | else => null, | 1531 | else => unreachable, |
| 1547 | }, | 1532 | }, |
| 1548 | .rmi => return switch (tag) { | 1533 | .rmi => return switch (tag) { |
| 1549 | .imul => OpCode.oneByte(if (is_one_byte) 0x6b else 0x69), | 1534 | .imul => OpCode.oneByte(if (is_one_byte) 0x6b else 0x69), |
| 1550 | else => null, | 1535 | else => unreachable, |
| 1551 | }, | 1536 | }, |
| 1552 | .mv => return switch (tag) { | 1537 | .mv => return switch (tag) { |
| 1553 | .vmovsd => OpCode.oneByte(0x11), | 1538 | .vmovsd, .vmovss => OpCode.oneByte(0x11), |
| 1554 | else => null, | 1539 | else => unreachable, |
| 1555 | }, | 1540 | }, |
| 1556 | .vm => return switch (tag) { | 1541 | .vm => return switch (tag) { |
| 1557 | .vmovsd => OpCode.oneByte(0x10), | 1542 | .vmovsd, .vmovss => OpCode.oneByte(0x10), |
| 1558 | .vucomisd => OpCode.oneByte(0x2e), | 1543 | .vucomisd, .vucomiss => OpCode.oneByte(0x2e), |
| 1559 | else => null, | 1544 | else => unreachable, |
| 1560 | }, | 1545 | }, |
| 1561 | .rvm => return switch (tag) { | 1546 | .rvm => return switch (tag) { |
| 1562 | .vaddsd => OpCode.oneByte(0x58), | 1547 | .vaddsd, .vaddss => OpCode.oneByte(0x58), |
| 1563 | .vmovsd => OpCode.oneByte(0x10), | 1548 | .vmovsd, .vmovss => OpCode.oneByte(0x10), |
| 1564 | else => null, | 1549 | else => unreachable, |
| 1565 | }, | 1550 | }, |
| 1566 | .rvmi => return switch (tag) { | 1551 | .rvmi => return switch (tag) { |
| 1567 | .vcmpsd => OpCode.oneByte(0xc2), | 1552 | .vcmpsd, .vcmpss => OpCode.oneByte(0xc2), |
| 1568 | else => null, | 1553 | else => unreachable, |
| 1569 | }, | 1554 | }, |
| 1570 | } | 1555 | } |
| 1571 | } | 1556 | } |
| 1572 | | 1557 | |
| 1573 | inline fn getModRmExt(tag: Tag) ?u3 { | 1558 | inline fn getModRmExt(tag: Tag) u3 { |
| 1574 | return switch (tag) { | 1559 | return switch (tag) { |
| 1575 | .adc => 0x2, | 1560 | .adc => 0x2, |
| 1576 | .add => 0x0, | 1561 | .add => 0x0, |
| ... | @@ -1631,11 +1616,11 @@ inline fn getModRmExt(tag: Tag) ?u3 { | ... | @@ -1631,11 +1616,11 @@ inline fn getModRmExt(tag: Tag) ?u3 { |
| 1631 | .fisttp64 => 0x1, | 1616 | .fisttp64 => 0x1, |
| 1632 | .fld32 => 0x0, | 1617 | .fld32 => 0x0, |
| 1633 | .fld64 => 0x0, | 1618 | .fld64 => 0x0, |
| 1634 | else => null, | 1619 | else => unreachable, |
| 1635 | }; | 1620 | }; |
| 1636 | } | 1621 | } |
| 1637 | | 1622 | |
| 1638 | const VexPrefix = struct { | 1623 | const VexEncoding = struct { |
| 1639 | prefix: Encoder.Vex, | 1624 | prefix: Encoder.Vex, |
| 1640 | reg: ?enum { | 1625 | reg: ?enum { |
| 1641 | ndd, | 1626 | ndd, |
| ... | @@ -1644,7 +1629,7 @@ const VexPrefix = struct { | ... | @@ -1644,7 +1629,7 @@ const VexPrefix = struct { |
| 1644 | }, | 1629 | }, |
| 1645 | }; | 1630 | }; |
| 1646 | | 1631 | |
| 1647 | inline fn getVexPrefix(tag: Tag, enc: Encoding) ?VexPrefix { | 1632 | inline fn getVexEncoding(tag: Tag, enc: Encoding) VexEncoding { |
| 1648 | const desc: struct { | 1633 | const desc: struct { |
| 1649 | reg: enum { | 1634 | reg: enum { |
| 1650 | none, | 1635 | none, |
| ... | @@ -1671,21 +1656,27 @@ inline fn getVexPrefix(tag: Tag, enc: Encoding) ?VexPrefix { | ... | @@ -1671,21 +1656,27 @@ inline fn getVexPrefix(tag: Tag, enc: Encoding) ?VexPrefix { |
| 1671 | switch (enc) { | 1656 | switch (enc) { |
| 1672 | .mv => switch (tag) { | 1657 | .mv => switch (tag) { |
| 1673 | .vmovsd => break :blk .{ .lig = true, .simd_prefix = .p_f2, .wig = true }, | 1658 | .vmovsd => break :blk .{ .lig = true, .simd_prefix = .p_f2, .wig = true }, |
| 1674 | else => return null, | 1659 | .vmovss => break :blk .{ .lig = true, .simd_prefix = .p_f3, .wig = true }, |
| | 1660 | else => unreachable, |
| 1675 | }, | 1661 | }, |
| 1676 | .vm => switch (tag) { | 1662 | .vm => switch (tag) { |
| 1677 | .vmovsd => break :blk .{ .lig = true, .simd_prefix = .p_f2, .wig = true }, | 1663 | .vmovsd => break :blk .{ .lig = true, .simd_prefix = .p_f2, .wig = true }, |
| | 1664 | .vmovss => break :blk .{ .lig = true, .simd_prefix = .p_f3, .wig = true }, |
| 1678 | .vucomisd => break :blk .{ .lig = true, .simd_prefix = .p_66, .wig = true }, | 1665 | .vucomisd => break :blk .{ .lig = true, .simd_prefix = .p_66, .wig = true }, |
| 1679 | else => return null, | 1666 | .vucomiss => break :blk .{ .lig = true, .wig = true }, |
| | 1667 | else => unreachable, |
| 1680 | }, | 1668 | }, |
| 1681 | .rvm => switch (tag) { | 1669 | .rvm => switch (tag) { |
| 1682 | .vaddsd => break :blk .{ .reg = .nds, .lig = true, .simd_prefix = .p_f2, .wig = true }, | 1670 | .vaddsd => break :blk .{ .reg = .nds, .lig = true, .simd_prefix = .p_f2, .wig = true }, |
| | 1671 | .vaddss => break :blk .{ .reg = .nds, .lig = true, .simd_prefix = .p_f3, .wig = true }, |
| 1683 | .vmovsd => break :blk .{ .reg = .nds, .lig = true, .simd_prefix = .p_f2, .wig = true }, | 1672 | .vmovsd => break :blk .{ .reg = .nds, .lig = true, .simd_prefix = .p_f2, .wig = true }, |
| 1684 | else => return null, | 1673 | .vmovss => break :blk .{ .reg = .nds, .lig = true, .simd_prefix = .p_f3, .wig = true }, |
| | 1674 | else => unreachable, |
| 1685 | }, | 1675 | }, |
| 1686 | .rvmi => switch (tag) { | 1676 | .rvmi => switch (tag) { |
| 1687 | .vcmpsd => break :blk .{ .reg = .nds, .lig = true, .simd_prefix = .p_f2, .wig = true }, | 1677 | .vcmpsd => break :blk .{ .reg = .nds, .lig = true, .simd_prefix = .p_f2, .wig = true }, |
| 1688 | else => return null, | 1678 | .vcmpss => break :blk .{ .reg = .nds, .lig = true, .simd_prefix = .p_f3, .wig = true }, |
| | 1679 | else => unreachable, |
| 1689 | }, | 1680 | }, |
| 1690 | else => unreachable, | 1681 | else => unreachable, |
| 1691 | } | 1682 | } |
| ... | @@ -1711,7 +1702,7 @@ inline fn getVexPrefix(tag: Tag, enc: Encoding) ?VexPrefix { | ... | @@ -1711,7 +1702,7 @@ inline fn getVexPrefix(tag: Tag, enc: Encoding) ?VexPrefix { |
| 1711 | .p_f3 => vex.simd_prefix_f3(), | 1702 | .p_f3 => vex.simd_prefix_f3(), |
| 1712 | } | 1703 | } |
| 1713 | | 1704 | |
| 1714 | return VexPrefix{ .prefix = vex, .reg = switch (desc.reg) { | 1705 | return VexEncoding{ .prefix = vex, .reg = switch (desc.reg) { |
| 1715 | .none => null, | 1706 | .none => null, |
| 1716 | .nds => .nds, | 1707 | .nds => .nds, |
| 1717 | .dds => .dds, | 1708 | .dds => .dds, |
| ... | @@ -1862,7 +1853,7 @@ const RegisterOrMemory = union(enum) { | ... | @@ -1862,7 +1853,7 @@ const RegisterOrMemory = union(enum) { |
| 1862 | | 1853 | |
| 1863 | fn lowerToZoEnc(tag: Tag, code: *std.ArrayList(u8)) InnerError!void { | 1854 | fn lowerToZoEnc(tag: Tag, code: *std.ArrayList(u8)) InnerError!void { |
| 1864 | assert(!tag.isAvx()); | 1855 | assert(!tag.isAvx()); |
| 1865 | const opc = getOpCode(tag, .zo, false).?; | 1856 | const opc = getOpCode(tag, .zo, false); |
| 1866 | const encoder = try Encoder.init(code, 2); | 1857 | const encoder = try Encoder.init(code, 2); |
| 1867 | switch (tag) { | 1858 | switch (tag) { |
| 1868 | .cqo => { | 1859 | .cqo => { |
| ... | @@ -1879,12 +1870,12 @@ fn lowerToIEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void { | ... | @@ -1879,12 +1870,12 @@ fn lowerToIEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void { |
| 1879 | assert(!tag.isAvx()); | 1870 | assert(!tag.isAvx()); |
| 1880 | if (tag == .ret_far or tag == .ret_near) { | 1871 | if (tag == .ret_far or tag == .ret_near) { |
| 1881 | const encoder = try Encoder.init(code, 3); | 1872 | const encoder = try Encoder.init(code, 3); |
| 1882 | const opc = getOpCode(tag, .i, false).?; | 1873 | const opc = getOpCode(tag, .i, false); |
| 1883 | opc.encode(encoder); | 1874 | opc.encode(encoder); |
| 1884 | encoder.imm16(@bitCast(i16, @truncate(u16, imm))); | 1875 | encoder.imm16(@bitCast(i16, @truncate(u16, imm))); |
| 1885 | return; | 1876 | return; |
| 1886 | } | 1877 | } |
| 1887 | const opc = getOpCode(tag, .i, immOpSize(imm) == 8).?; | 1878 | const opc = getOpCode(tag, .i, immOpSize(imm) == 8); |
| 1888 | const encoder = try Encoder.init(code, 5); | 1879 | const encoder = try Encoder.init(code, 5); |
| 1889 | if (immOpSize(imm) == 16) { | 1880 | if (immOpSize(imm) == 16) { |
| 1890 | encoder.prefix16BitMode(); | 1881 | encoder.prefix16BitMode(); |
| ... | @@ -1895,7 +1886,7 @@ fn lowerToIEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void { | ... | @@ -1895,7 +1886,7 @@ fn lowerToIEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void { |
| 1895 | | 1886 | |
| 1896 | fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!void { | 1887 | fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!void { |
| 1897 | assert(!tag.isAvx()); | 1888 | assert(!tag.isAvx()); |
| 1898 | const opc = getOpCode(tag, .o, false).?; | 1889 | const opc = getOpCode(tag, .o, false); |
| 1899 | const encoder = try Encoder.init(code, 3); | 1890 | const encoder = try Encoder.init(code, 3); |
| 1900 | if (reg.size() == 16) { | 1891 | if (reg.size() == 16) { |
| 1901 | encoder.prefix16BitMode(); | 1892 | encoder.prefix16BitMode(); |
| ... | @@ -1909,7 +1900,7 @@ fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!voi | ... | @@ -1909,7 +1900,7 @@ fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!voi |
| 1909 | | 1900 | |
| 1910 | fn lowerToDEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void { | 1901 | fn lowerToDEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void { |
| 1911 | assert(!tag.isAvx()); | 1902 | assert(!tag.isAvx()); |
| 1912 | const opc = getOpCode(tag, .d, false).?; | 1903 | const opc = getOpCode(tag, .d, false); |
| 1913 | const encoder = try Encoder.init(code, 6); | 1904 | const encoder = try Encoder.init(code, 6); |
| 1914 | opc.encode(encoder); | 1905 | opc.encode(encoder); |
| 1915 | encoder.imm32(@bitCast(i32, imm)); | 1906 | encoder.imm32(@bitCast(i32, imm)); |
| ... | @@ -1917,8 +1908,8 @@ fn lowerToDEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void { | ... | @@ -1917,8 +1908,8 @@ fn lowerToDEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void { |
| 1917 | | 1908 | |
| 1918 | fn lowerToMxEnc(tag: Tag, reg_or_mem: RegisterOrMemory, enc: Encoding, code: *std.ArrayList(u8)) InnerError!void { | 1909 | fn lowerToMxEnc(tag: Tag, reg_or_mem: RegisterOrMemory, enc: Encoding, code: *std.ArrayList(u8)) InnerError!void { |
| 1919 | assert(!tag.isAvx()); | 1910 | assert(!tag.isAvx()); |
| 1920 | const opc = getOpCode(tag, enc, reg_or_mem.size() == 8).?; | 1911 | const opc = getOpCode(tag, enc, reg_or_mem.size() == 8); |
| 1921 | const modrm_ext = getModRmExt(tag).?; | 1912 | const modrm_ext = getModRmExt(tag); |
| 1922 | switch (reg_or_mem) { | 1913 | switch (reg_or_mem) { |
| 1923 | .register => |reg| { | 1914 | .register => |reg| { |
| 1924 | const encoder = try Encoder.init(code, 4); | 1915 | const encoder = try Encoder.init(code, 4); |
| ... | @@ -1973,10 +1964,7 @@ fn lowerToFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8)) I | ... | @@ -1973,10 +1964,7 @@ fn lowerToFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8)) I |
| 1973 | | 1964 | |
| 1974 | fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8), td: bool) InnerError!void { | 1965 | fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8), td: bool) InnerError!void { |
| 1975 | assert(!tag.isAvx()); | 1966 | assert(!tag.isAvx()); |
| 1976 | const opc = if (td) | 1967 | const opc = if (td) getOpCode(tag, .td, reg.size() == 8) else getOpCode(tag, .fd, reg.size() == 8); |
| 1977 | getOpCode(tag, .td, reg.size() == 8).? | | |
| 1978 | else | | |
| 1979 | getOpCode(tag, .fd, reg.size() == 8).?; | | |
| 1980 | const encoder = try Encoder.init(code, 10); | 1968 | const encoder = try Encoder.init(code, 10); |
| 1981 | if (reg.size() == 16) { | 1969 | if (reg.size() == 16) { |
| 1982 | encoder.prefix16BitMode(); | 1970 | encoder.prefix16BitMode(); |
| ... | @@ -1996,7 +1984,7 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8), | ... | @@ -1996,7 +1984,7 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8), |
| 1996 | | 1984 | |
| 1997 | fn lowerToOiEnc(tag: Tag, reg: Register, imm: u64, code: *std.ArrayList(u8)) InnerError!void { | 1985 | fn lowerToOiEnc(tag: Tag, reg: Register, imm: u64, code: *std.ArrayList(u8)) InnerError!void { |
| 1998 | assert(!tag.isAvx()); | 1986 | assert(!tag.isAvx()); |
| 1999 | const opc = getOpCode(tag, .oi, reg.size() == 8).?; | 1987 | const opc = getOpCode(tag, .oi, reg.size() == 8); |
| 2000 | const encoder = try Encoder.init(code, 10); | 1988 | const encoder = try Encoder.init(code, 10); |
| 2001 | if (reg.size() == 16) { | 1989 | if (reg.size() == 16) { |
| 2002 | encoder.prefix16BitMode(); | 1990 | encoder.prefix16BitMode(); |
| ... | @@ -2023,8 +2011,8 @@ fn lowerToMiXEnc( | ... | @@ -2023,8 +2011,8 @@ fn lowerToMiXEnc( |
| 2023 | code: *std.ArrayList(u8), | 2011 | code: *std.ArrayList(u8), |
| 2024 | ) InnerError!void { | 2012 | ) InnerError!void { |
| 2025 | assert(!tag.isAvx()); | 2013 | assert(!tag.isAvx()); |
| 2026 | const modrm_ext = getModRmExt(tag).?; | 2014 | const modrm_ext = getModRmExt(tag); |
| 2027 | const opc = getOpCode(tag, enc, reg_or_mem.size() == 8).?; | 2015 | const opc = getOpCode(tag, enc, reg_or_mem.size() == 8); |
| 2028 | switch (reg_or_mem) { | 2016 | switch (reg_or_mem) { |
| 2029 | .register => |dst_reg| { | 2017 | .register => |dst_reg| { |
| 2030 | const encoder = try Encoder.init(code, 7); | 2018 | const encoder = try Encoder.init(code, 7); |
| ... | @@ -2079,7 +2067,7 @@ fn lowerToRmEnc( | ... | @@ -2079,7 +2067,7 @@ fn lowerToRmEnc( |
| 2079 | code: *std.ArrayList(u8), | 2067 | code: *std.ArrayList(u8), |
| 2080 | ) InnerError!void { | 2068 | ) InnerError!void { |
| 2081 | assert(!tag.isAvx()); | 2069 | assert(!tag.isAvx()); |
| 2082 | const opc = getOpCode(tag, .rm, reg.size() == 8 or reg_or_mem.size() == 8).?; | 2070 | const opc = getOpCode(tag, .rm, reg.size() == 8 or reg_or_mem.size() == 8); |
| 2083 | switch (reg_or_mem) { | 2071 | switch (reg_or_mem) { |
| 2084 | .register => |src_reg| { | 2072 | .register => |src_reg| { |
| 2085 | const encoder = try Encoder.init(code, 5); | 2073 | const encoder = try Encoder.init(code, 5); |
| ... | @@ -2126,7 +2114,7 @@ fn lowerToMrEnc( | ... | @@ -2126,7 +2114,7 @@ fn lowerToMrEnc( |
| 2126 | code: *std.ArrayList(u8), | 2114 | code: *std.ArrayList(u8), |
| 2127 | ) InnerError!void { | 2115 | ) InnerError!void { |
| 2128 | assert(!tag.isAvx()); | 2116 | assert(!tag.isAvx()); |
| 2129 | const opc = getOpCode(tag, .mr, reg.size() == 8 or reg_or_mem.size() == 8).?; | 2117 | const opc = getOpCode(tag, .mr, reg.size() == 8 or reg_or_mem.size() == 8); |
| 2130 | switch (reg_or_mem) { | 2118 | switch (reg_or_mem) { |
| 2131 | .register => |dst_reg| { | 2119 | .register => |dst_reg| { |
| 2132 | const encoder = try Encoder.init(code, 4); | 2120 | const encoder = try Encoder.init(code, 4); |
| ... | @@ -2172,7 +2160,7 @@ fn lowerToRmiEnc( | ... | @@ -2172,7 +2160,7 @@ fn lowerToRmiEnc( |
| 2172 | code: *std.ArrayList(u8), | 2160 | code: *std.ArrayList(u8), |
| 2173 | ) InnerError!void { | 2161 | ) InnerError!void { |
| 2174 | assert(!tag.isAvx()); | 2162 | assert(!tag.isAvx()); |
| 2175 | const opc = getOpCode(tag, .rmi, false).?; | 2163 | const opc = getOpCode(tag, .rmi, false); |
| 2176 | const encoder = try Encoder.init(code, 13); | 2164 | const encoder = try Encoder.init(code, 13); |
| 2177 | if (reg.size() == 16) { | 2165 | if (reg.size() == 16) { |
| 2178 | encoder.prefix16BitMode(); | 2166 | encoder.prefix16BitMode(); |
| ... | @@ -2216,9 +2204,9 @@ fn lowerToVmEnc( | ... | @@ -2216,9 +2204,9 @@ fn lowerToVmEnc( |
| 2216 | reg_or_mem: RegisterOrMemory, | 2204 | reg_or_mem: RegisterOrMemory, |
| 2217 | code: *std.ArrayList(u8), | 2205 | code: *std.ArrayList(u8), |
| 2218 | ) InnerError!void { | 2206 | ) InnerError!void { |
| 2219 | const opc = getOpCode(tag, .vm, false).?; | 2207 | const opc = getOpCode(tag, .vm, false); |
| 2220 | var vex_prefix = getVexPrefix(tag, .vm).?; | 2208 | var enc = getVexEncoding(tag, .vm); |
| 2221 | const vex = &vex_prefix.prefix; | 2209 | const vex = &enc.prefix; |
| 2222 | switch (reg_or_mem) { | 2210 | switch (reg_or_mem) { |
| 2223 | .register => |src_reg| { | 2211 | .register => |src_reg| { |
| 2224 | const encoder = try Encoder.init(code, 5); | 2212 | const encoder = try Encoder.init(code, 5); |
| ... | @@ -2226,12 +2214,11 @@ fn lowerToVmEnc( | ... | @@ -2226,12 +2214,11 @@ fn lowerToVmEnc( |
| 2226 | .r = reg.isExtended(), | 2214 | .r = reg.isExtended(), |
| 2227 | .b = src_reg.isExtended(), | 2215 | .b = src_reg.isExtended(), |
| 2228 | }); | 2216 | }); |
| 2229 | encoder.vex(vex_prefix.prefix); | 2217 | encoder.vex(enc.prefix); |
| 2230 | opc.encode(encoder); | 2218 | opc.encode(encoder); |
| 2231 | encoder.modRm_direct(reg.lowEnc(), src_reg.lowEnc()); | 2219 | encoder.modRm_direct(reg.lowEnc(), src_reg.lowEnc()); |
| 2232 | }, | 2220 | }, |
| 2233 | .memory => |src_mem| { | 2221 | .memory => |src_mem| { |
| 2234 | assert(src_mem.ptr_size == .qword_ptr); | | |
| 2235 | const encoder = try Encoder.init(code, 10); | 2222 | const encoder = try Encoder.init(code, 10); |
| 2236 | if (src_mem.base) |base| { | 2223 | if (src_mem.base) |base| { |
| 2237 | vex.rex(.{ | 2224 | vex.rex(.{ |
| ... | @@ -2243,7 +2230,7 @@ fn lowerToVmEnc( | ... | @@ -2243,7 +2230,7 @@ fn lowerToVmEnc( |
| 2243 | .r = reg.isExtended(), | 2230 | .r = reg.isExtended(), |
| 2244 | }); | 2231 | }); |
| 2245 | } | 2232 | } |
| 2246 | encoder.vex(vex_prefix.prefix); | 2233 | encoder.vex(enc.prefix); |
| 2247 | opc.encode(encoder); | 2234 | opc.encode(encoder); |
| 2248 | src_mem.encode(encoder, reg.lowEnc()); | 2235 | src_mem.encode(encoder, reg.lowEnc()); |
| 2249 | }, | 2236 | }, |
| ... | @@ -2257,9 +2244,9 @@ fn lowerToMvEnc( | ... | @@ -2257,9 +2244,9 @@ fn lowerToMvEnc( |
| 2257 | reg: Register, | 2244 | reg: Register, |
| 2258 | code: *std.ArrayList(u8), | 2245 | code: *std.ArrayList(u8), |
| 2259 | ) InnerError!void { | 2246 | ) InnerError!void { |
| 2260 | const opc = getOpCode(tag, .mv, false).?; | 2247 | const opc = getOpCode(tag, .mv, false); |
| 2261 | var vex_prefix = getVexPrefix(tag, .mv).?; | 2248 | var enc = getVexEncoding(tag, .mv); |
| 2262 | const vex = &vex_prefix.prefix; | 2249 | const vex = &enc.prefix; |
| 2263 | switch (reg_or_mem) { | 2250 | switch (reg_or_mem) { |
| 2264 | .register => |dst_reg| { | 2251 | .register => |dst_reg| { |
| 2265 | const encoder = try Encoder.init(code, 4); | 2252 | const encoder = try Encoder.init(code, 4); |
| ... | @@ -2267,12 +2254,11 @@ fn lowerToMvEnc( | ... | @@ -2267,12 +2254,11 @@ fn lowerToMvEnc( |
| 2267 | .r = reg.isExtended(), | 2254 | .r = reg.isExtended(), |
| 2268 | .b = dst_reg.isExtended(), | 2255 | .b = dst_reg.isExtended(), |
| 2269 | }); | 2256 | }); |
| 2270 | encoder.vex(vex_prefix.prefix); | 2257 | encoder.vex(enc.prefix); |
| 2271 | opc.encode(encoder); | 2258 | opc.encode(encoder); |
| 2272 | encoder.modRm_direct(reg.lowEnc(), dst_reg.lowEnc()); | 2259 | encoder.modRm_direct(reg.lowEnc(), dst_reg.lowEnc()); |
| 2273 | }, | 2260 | }, |
| 2274 | .memory => |dst_mem| { | 2261 | .memory => |dst_mem| { |
| 2275 | assert(dst_mem.ptr_size == .qword_ptr); | | |
| 2276 | const encoder = try Encoder.init(code, 10); | 2262 | const encoder = try Encoder.init(code, 10); |
| 2277 | if (dst_mem.base) |base| { | 2263 | if (dst_mem.base) |base| { |
| 2278 | vex.rex(.{ | 2264 | vex.rex(.{ |
| ... | @@ -2284,7 +2270,7 @@ fn lowerToMvEnc( | ... | @@ -2284,7 +2270,7 @@ fn lowerToMvEnc( |
| 2284 | .r = reg.isExtended(), | 2270 | .r = reg.isExtended(), |
| 2285 | }); | 2271 | }); |
| 2286 | } | 2272 | } |
| 2287 | encoder.vex(vex_prefix.prefix); | 2273 | encoder.vex(enc.prefix); |
| 2288 | opc.encode(encoder); | 2274 | opc.encode(encoder); |
| 2289 | dst_mem.encode(encoder, reg.lowEnc()); | 2275 | dst_mem.encode(encoder, reg.lowEnc()); |
| 2290 | }, | 2276 | }, |
| ... | @@ -2298,12 +2284,12 @@ fn lowerToRvmEnc( | ... | @@ -2298,12 +2284,12 @@ fn lowerToRvmEnc( |
| 2298 | reg_or_mem: RegisterOrMemory, | 2284 | reg_or_mem: RegisterOrMemory, |
| 2299 | code: *std.ArrayList(u8), | 2285 | code: *std.ArrayList(u8), |
| 2300 | ) InnerError!void { | 2286 | ) InnerError!void { |
| 2301 | const opc = getOpCode(tag, .rvm, false).?; | 2287 | const opc = getOpCode(tag, .rvm, false); |
| 2302 | var vex_prefix = getVexPrefix(tag, .rvm).?; | 2288 | var enc = getVexEncoding(tag, .rvm); |
| 2303 | const vex = &vex_prefix.prefix; | 2289 | const vex = &enc.prefix; |
| 2304 | switch (reg_or_mem) { | 2290 | switch (reg_or_mem) { |
| 2305 | .register => |reg3| { | 2291 | .register => |reg3| { |
| 2306 | if (vex_prefix.reg) |vvvv| { | 2292 | if (enc.reg) |vvvv| { |
| 2307 | switch (vvvv) { | 2293 | switch (vvvv) { |
| 2308 | .nds => vex.reg(reg2.enc()), | 2294 | .nds => vex.reg(reg2.enc()), |
| 2309 | else => unreachable, // TODO | 2295 | else => unreachable, // TODO |
| ... | @@ -2314,7 +2300,7 @@ fn lowerToRvmEnc( | ... | @@ -2314,7 +2300,7 @@ fn lowerToRvmEnc( |
| 2314 | .r = reg1.isExtended(), | 2300 | .r = reg1.isExtended(), |
| 2315 | .b = reg3.isExtended(), | 2301 | .b = reg3.isExtended(), |
| 2316 | }); | 2302 | }); |
| 2317 | encoder.vex(vex_prefix.prefix); | 2303 | encoder.vex(enc.prefix); |
| 2318 | opc.encode(encoder); | 2304 | opc.encode(encoder); |
| 2319 | encoder.modRm_direct(reg1.lowEnc(), reg3.lowEnc()); | 2305 | encoder.modRm_direct(reg1.lowEnc(), reg3.lowEnc()); |
| 2320 | }, | 2306 | }, |
| ... | @@ -2333,13 +2319,13 @@ fn lowerToRvmiEnc( | ... | @@ -2333,13 +2319,13 @@ fn lowerToRvmiEnc( |
| 2333 | imm: u32, | 2319 | imm: u32, |
| 2334 | code: *std.ArrayList(u8), | 2320 | code: *std.ArrayList(u8), |
| 2335 | ) InnerError!void { | 2321 | ) InnerError!void { |
| 2336 | const opc = getOpCode(tag, .rvmi, false).?; | 2322 | const opc = getOpCode(tag, .rvmi, false); |
| 2337 | var vex_prefix = getVexPrefix(tag, .rvmi).?; | 2323 | var enc = getVexEncoding(tag, .rvmi); |
| 2338 | const vex = &vex_prefix.prefix; | 2324 | const vex = &enc.prefix; |
| 2339 | const encoder: Encoder = blk: { | 2325 | const encoder: Encoder = blk: { |
| 2340 | switch (reg_or_mem) { | 2326 | switch (reg_or_mem) { |
| 2341 | .register => |reg3| { | 2327 | .register => |reg3| { |
| 2342 | if (vex_prefix.reg) |vvvv| { | 2328 | if (enc.reg) |vvvv| { |
| 2343 | switch (vvvv) { | 2329 | switch (vvvv) { |
| 2344 | .nds => vex.reg(reg2.enc()), | 2330 | .nds => vex.reg(reg2.enc()), |
| 2345 | else => unreachable, // TODO | 2331 | else => unreachable, // TODO |
| ... | @@ -2350,7 +2336,7 @@ fn lowerToRvmiEnc( | ... | @@ -2350,7 +2336,7 @@ fn lowerToRvmiEnc( |
| 2350 | .r = reg1.isExtended(), | 2336 | .r = reg1.isExtended(), |
| 2351 | .b = reg3.isExtended(), | 2337 | .b = reg3.isExtended(), |
| 2352 | }); | 2338 | }); |
| 2353 | encoder.vex(vex_prefix.prefix); | 2339 | encoder.vex(enc.prefix); |
| 2354 | opc.encode(encoder); | 2340 | opc.encode(encoder); |
| 2355 | encoder.modRm_direct(reg1.lowEnc(), reg3.lowEnc()); | 2341 | encoder.modRm_direct(reg1.lowEnc(), reg3.lowEnc()); |
| 2356 | break :blk encoder; | 2342 | break :blk encoder; |