| ... | @@ -182,6 +182,16 @@ pub fn lowerMir(emit: *Emit) InnerError!void { | ... | @@ -182,6 +182,16 @@ pub fn lowerMir(emit: *Emit) InnerError!void { |
| 182 | .interrupt => try emit.mirInterrupt(inst), | 182 | .interrupt => try emit.mirInterrupt(inst), |
| 183 | .nop => try emit.mirNop(), | 183 | .nop => try emit.mirNop(), |
| 184 | | 184 | |
| | 185 | // SSE instructions |
| | 186 | .mov_f64_sse => try emit.mirMovFloatSse(.movsd, inst), |
| | 187 | .mov_f32_sse => try emit.mirMovFloatSse(.movss, inst), |
| | 188 | |
| | 189 | .add_f64_sse => try emit.mirAddFloatSse(.addsd, inst), |
| | 190 | .add_f32_sse => try emit.mirAddFloatSse(.addss, inst), |
| | 191 | |
| | 192 | .cmp_f64_sse => try emit.mirCmpFloatSse(.ucomisd, inst), |
| | 193 | .cmp_f32_sse => try emit.mirCmpFloatSse(.ucomiss, inst), |
| | 194 | |
| 185 | // AVX instructions | 195 | // AVX instructions |
| 186 | .mov_f64_avx => try emit.mirMovFloatAvx(.vmovsd, inst), | 196 | .mov_f64_avx => try emit.mirMovFloatAvx(.vmovsd, inst), |
| 187 | .mov_f32_avx => try emit.mirMovFloatAvx(.vmovss, inst), | 197 | .mov_f32_avx => try emit.mirMovFloatAvx(.vmovss, inst), |
| ... | @@ -536,6 +546,7 @@ fn mirArithMemImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -536,6 +546,7 @@ fn mirArithMemImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 536 | } | 546 | } |
| 537 | | 547 | |
| 538 | inline fn setRexWRegister(reg: Register) bool { | 548 | inline fn setRexWRegister(reg: Register) bool { |
| | 549 | if (reg.size() > 64) return false; |
| 539 | if (reg.size() == 64) return true; | 550 | if (reg.size() == 64) return true; |
| 540 | return switch (reg) { | 551 | return switch (reg) { |
| 541 | .ah, .ch, .dh, .bh => true, | 552 | .ah, .ch, .dh, .bh => true, |
| ... | @@ -963,11 +974,55 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -963,11 +974,55 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 963 | } | 974 | } |
| 964 | } | 975 | } |
| 965 | | 976 | |
| | 977 | // SSE instructions |
| | 978 | |
| | 979 | fn mirMovFloatSse(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| | 980 | const ops = emit.mir.instructions.items(.ops)[inst].decode(); |
| | 981 | switch (ops.flags) { |
| | 982 | 0b00 => { |
| | 983 | const imm = emit.mir.instructions.items(.data)[inst].imm; |
| | 984 | return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.new(ops.reg2.size()), .{ |
| | 985 | .disp = imm, |
| | 986 | .base = ops.reg2, |
| | 987 | }), emit.code); |
| | 988 | }, |
| | 989 | 0b01 => { |
| | 990 | const imm = emit.mir.instructions.items(.data)[inst].imm; |
| | 991 | return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.new(ops.reg1.size()), .{ |
| | 992 | .disp = imm, |
| | 993 | .base = ops.reg1, |
| | 994 | }), ops.reg2, emit.code); |
| | 995 | }, |
| | 996 | 0b10 => { |
| | 997 | return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code); |
| | 998 | }, |
| | 999 | else => return emit.fail("TODO unused variant 0b{b} for {}", .{ ops.flags, tag }), |
| | 1000 | } |
| | 1001 | } |
| | 1002 | |
| | 1003 | fn mirAddFloatSse(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| | 1004 | const ops = emit.mir.instructions.items(.ops)[inst].decode(); |
| | 1005 | switch (ops.flags) { |
| | 1006 | 0b00 => { |
| | 1007 | return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code); |
| | 1008 | }, |
| | 1009 | else => return emit.fail("TODO unused variant 0b{b} for {}", .{ ops.flags, tag }), |
| | 1010 | } |
| | 1011 | } |
| | 1012 | |
| | 1013 | fn mirCmpFloatSse(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| | 1014 | const ops = emit.mir.instructions.items(.ops)[inst].decode(); |
| | 1015 | switch (ops.flags) { |
| | 1016 | 0b00 => { |
| | 1017 | return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code); |
| | 1018 | }, |
| | 1019 | else => return emit.fail("TODO unused variant 0b{b} for {}", .{ ops.flags, tag }), |
| | 1020 | } |
| | 1021 | } |
| 966 | // AVX instructions | 1022 | // AVX instructions |
| 967 | | 1023 | |
| 968 | fn mirMovFloatAvx(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | 1024 | fn mirMovFloatAvx(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 969 | const ops = emit.mir.instructions.items(.ops)[inst].decode(); | 1025 | const ops = emit.mir.instructions.items(.ops)[inst].decode(); |
| 970 | | | |
| 971 | switch (ops.flags) { | 1026 | switch (ops.flags) { |
| 972 | 0b00 => { | 1027 | 0b00 => { |
| 973 | const imm = emit.mir.instructions.items(.data)[inst].imm; | 1028 | const imm = emit.mir.instructions.items(.data)[inst].imm; |
| ... | @@ -986,24 +1041,22 @@ fn mirMovFloatAvx(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -986,24 +1041,22 @@ fn mirMovFloatAvx(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 986 | 0b10 => { | 1041 | 0b10 => { |
| 987 | return lowerToRvmEnc(tag, ops.reg1, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code); | 1042 | return lowerToRvmEnc(tag, ops.reg1, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code); |
| 988 | }, | 1043 | }, |
| 989 | else => return emit.fail("TODO unused variant 0b{b} for mov_f64", .{ops.flags}), | 1044 | else => return emit.fail("TODO unused variant 0b{b} for {}", .{ ops.flags, tag }), |
| 990 | } | 1045 | } |
| 991 | } | 1046 | } |
| 992 | | 1047 | |
| 993 | fn mirAddFloatAvx(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | 1048 | fn mirAddFloatAvx(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 994 | const ops = emit.mir.instructions.items(.ops)[inst].decode(); | 1049 | const ops = emit.mir.instructions.items(.ops)[inst].decode(); |
| 995 | | | |
| 996 | switch (ops.flags) { | 1050 | switch (ops.flags) { |
| 997 | 0b00 => { | 1051 | 0b00 => { |
| 998 | return lowerToRvmEnc(tag, ops.reg1, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code); | 1052 | return lowerToRvmEnc(tag, ops.reg1, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code); |
| 999 | }, | 1053 | }, |
| 1000 | else => return emit.fail("TODO unused variant 0b{b} for mov_f64", .{ops.flags}), | 1054 | else => return emit.fail("TODO unused variant 0b{b} for {}", .{ ops.flags, tag }), |
| 1001 | } | 1055 | } |
| 1002 | } | 1056 | } |
| 1003 | | 1057 | |
| 1004 | fn mirCmpFloatAvx(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | 1058 | fn mirCmpFloatAvx(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 1005 | const ops = emit.mir.instructions.items(.ops)[inst].decode(); | 1059 | const ops = emit.mir.instructions.items(.ops)[inst].decode(); |
| 1006 | | | |
| 1007 | switch (ops.flags) { | 1060 | switch (ops.flags) { |
| 1008 | 0b00 => { | 1061 | 0b00 => { |
| 1009 | return lowerToVmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code); | 1062 | return lowerToVmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code); |
| ... | @@ -1247,6 +1300,14 @@ const Tag = enum { | ... | @@ -1247,6 +1300,14 @@ const Tag = enum { |
| 1247 | cmovng, | 1300 | cmovng, |
| 1248 | cmovb, | 1301 | cmovb, |
| 1249 | cmovnae, | 1302 | cmovnae, |
| | 1303 | movsd, |
| | 1304 | movss, |
| | 1305 | addsd, |
| | 1306 | addss, |
| | 1307 | cmpsd, |
| | 1308 | cmpss, |
| | 1309 | ucomisd, |
| | 1310 | ucomiss, |
| 1250 | vmovsd, | 1311 | vmovsd, |
| 1251 | vmovss, | 1312 | vmovss, |
| 1252 | vaddsd, | 1313 | vaddsd, |
| ... | @@ -1256,6 +1317,22 @@ const Tag = enum { | ... | @@ -1256,6 +1317,22 @@ const Tag = enum { |
| 1256 | vucomisd, | 1317 | vucomisd, |
| 1257 | vucomiss, | 1318 | vucomiss, |
| 1258 | | 1319 | |
| | 1320 | fn isSse(tag: Tag) bool { |
| | 1321 | return switch (tag) { |
| | 1322 | .movsd, |
| | 1323 | .movss, |
| | 1324 | .addsd, |
| | 1325 | .addss, |
| | 1326 | .cmpsd, |
| | 1327 | .cmpss, |
| | 1328 | .ucomisd, |
| | 1329 | .ucomiss, |
| | 1330 | => true, |
| | 1331 | |
| | 1332 | else => false, |
| | 1333 | }; |
| | 1334 | } |
| | 1335 | |
| 1259 | fn isAvx(tag: Tag) bool { | 1336 | fn isAvx(tag: Tag) bool { |
| 1260 | return switch (tag) { | 1337 | return switch (tag) { |
| 1261 | .vmovsd, | 1338 | .vmovsd, |
| ... | @@ -1369,190 +1446,256 @@ const Encoding = enum { | ... | @@ -1369,190 +1446,256 @@ const Encoding = enum { |
| 1369 | rvmi, | 1446 | rvmi, |
| 1370 | }; | 1447 | }; |
| 1371 | | 1448 | |
| 1372 | const OpCode = union(enum) { | 1449 | const OpCode = struct { |
| 1373 | one_byte: u8, | 1450 | bytes: [3]u8, |
| 1374 | two_byte: struct { _1: u8, _2: u8 }, | 1451 | count: usize, |
| 1375 | | | |
| 1376 | fn oneByte(opc: u8) OpCode { | | |
| 1377 | return .{ .one_byte = opc }; | | |
| 1378 | } | | |
| 1379 | | 1452 | |
| 1380 | fn twoByte(opc1: u8, opc2: u8) OpCode { | 1453 | fn init(comptime in_bytes: []const u8) OpCode { |
| 1381 | return .{ .two_byte = .{ ._1 = opc1, ._2 = opc2 } }; | 1454 | comptime assert(in_bytes.len <= 3); |
| | 1455 | comptime var bytes: [3]u8 = undefined; |
| | 1456 | inline for (in_bytes) |x, i| { |
| | 1457 | bytes[i] = x; |
| | 1458 | } |
| | 1459 | return .{ .bytes = bytes, .count = in_bytes.len }; |
| 1382 | } | 1460 | } |
| 1383 | | 1461 | |
| 1384 | fn encode(opc: OpCode, encoder: Encoder) void { | 1462 | fn encode(opc: OpCode, encoder: Encoder) void { |
| 1385 | switch (opc) { | 1463 | switch (opc.count) { |
| 1386 | .one_byte => |v| encoder.opcode_1byte(v), | 1464 | 1 => encoder.opcode_1byte(opc.bytes[0]), |
| 1387 | .two_byte => |v| encoder.opcode_2byte(v._1, v._2), | 1465 | 2 => encoder.opcode_2byte(opc.bytes[0], opc.bytes[1]), |
| | 1466 | 3 => encoder.opcode_3byte(opc.bytes[0], opc.bytes[1], opc.bytes[2]), |
| | 1467 | else => unreachable, |
| 1388 | } | 1468 | } |
| 1389 | } | 1469 | } |
| 1390 | | 1470 | |
| 1391 | fn encodeWithReg(opc: OpCode, encoder: Encoder, reg: Register) void { | 1471 | fn encodeWithReg(opc: OpCode, encoder: Encoder, reg: Register) void { |
| 1392 | assert(opc == .one_byte); | 1472 | assert(opc.count == 1); |
| 1393 | encoder.opcode_withReg(opc.one_byte, reg.lowEnc()); | 1473 | encoder.opcode_withReg(opc.bytes[0], reg.lowEnc()); |
| 1394 | } | 1474 | } |
| 1395 | }; | 1475 | }; |
| 1396 | | 1476 | |
| 1397 | inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) OpCode { | 1477 | inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) OpCode { |
| | 1478 | // zig fmt: off |
| 1398 | switch (enc) { | 1479 | switch (enc) { |
| 1399 | .zo => return switch (tag) { | 1480 | .zo => return switch (tag) { |
| 1400 | .ret_near => OpCode.oneByte(0xc3), | 1481 | .ret_near => OpCode.init(&.{0xc3}), |
| 1401 | .ret_far => OpCode.oneByte(0xcb), | 1482 | .ret_far => OpCode.init(&.{0xcb}), |
| 1402 | .int3 => OpCode.oneByte(0xcc), | 1483 | .int3 => OpCode.init(&.{0xcc}), |
| 1403 | .nop => OpCode.oneByte(0x90), | 1484 | .nop => OpCode.init(&.{0x90}), |
| 1404 | .syscall => OpCode.twoByte(0x0f, 0x05), | 1485 | .syscall => OpCode.init(&.{ 0x0f, 0x05 }), |
| 1405 | .cbw => OpCode.oneByte(0x98), | 1486 | .cbw => OpCode.init(&.{0x98}), |
| 1406 | .cwd, .cdq, .cqo => OpCode.oneByte(0x99), | 1487 | .cwd, |
| 1407 | else => unreachable, | 1488 | .cdq, |
| | 1489 | .cqo => OpCode.init(&.{0x99}), |
| | 1490 | else => unreachable, |
| 1408 | }, | 1491 | }, |
| 1409 | .d => return switch (tag) { | 1492 | .d => return switch (tag) { |
| 1410 | .jmp_near => OpCode.oneByte(0xe9), | 1493 | .jmp_near => OpCode.init(&.{0xe9}), |
| 1411 | .call_near => OpCode.oneByte(0xe8), | 1494 | .call_near => OpCode.init(&.{0xe8}), |
| 1412 | .jo => if (is_one_byte) OpCode.oneByte(0x70) else OpCode.twoByte(0x0f, 0x80), | 1495 | .jo => if (is_one_byte) OpCode.init(&.{0x70}) else OpCode.init(&.{0x0f,0x80}), |
| 1413 | .jno => if (is_one_byte) OpCode.oneByte(0x71) else OpCode.twoByte(0x0f, 0x81), | 1496 | .jno => if (is_one_byte) OpCode.init(&.{0x71}) else OpCode.init(&.{0x0f,0x81}), |
| 1414 | .jb, .jc, .jnae => if (is_one_byte) OpCode.oneByte(0x72) else OpCode.twoByte(0x0f, 0x82), | 1497 | .jb, |
| 1415 | .jnb, .jnc, .jae => if (is_one_byte) OpCode.oneByte(0x73) else OpCode.twoByte(0x0f, 0x83), | 1498 | .jc, |
| 1416 | .je, .jz => if (is_one_byte) OpCode.oneByte(0x74) else OpCode.twoByte(0x0f, 0x84), | 1499 | .jnae => if (is_one_byte) OpCode.init(&.{0x72}) else OpCode.init(&.{0x0f,0x82}), |
| 1417 | .jne, .jnz => if (is_one_byte) OpCode.oneByte(0x75) else OpCode.twoByte(0x0f, 0x85), | 1500 | .jnb, |
| 1418 | .jna, .jbe => if (is_one_byte) OpCode.oneByte(0x76) else OpCode.twoByte(0x0f, 0x86), | 1501 | .jnc, |
| 1419 | .jnbe, .ja => if (is_one_byte) OpCode.oneByte(0x77) else OpCode.twoByte(0x0f, 0x87), | 1502 | .jae => if (is_one_byte) OpCode.init(&.{0x73}) else OpCode.init(&.{0x0f,0x83}), |
| 1420 | .js => if (is_one_byte) OpCode.oneByte(0x78) else OpCode.twoByte(0x0f, 0x88), | 1503 | .je, |
| 1421 | .jns => if (is_one_byte) OpCode.oneByte(0x79) else OpCode.twoByte(0x0f, 0x89), | 1504 | .jz => if (is_one_byte) OpCode.init(&.{0x74}) else OpCode.init(&.{0x0f,0x84}), |
| 1422 | .jpe, .jp => if (is_one_byte) OpCode.oneByte(0x7a) else OpCode.twoByte(0x0f, 0x8a), | 1505 | .jne, |
| 1423 | .jpo, .jnp => if (is_one_byte) OpCode.oneByte(0x7b) else OpCode.twoByte(0x0f, 0x8b), | 1506 | .jnz => if (is_one_byte) OpCode.init(&.{0x75}) else OpCode.init(&.{0x0f,0x85}), |
| 1424 | .jnge, .jl => if (is_one_byte) OpCode.oneByte(0x7c) else OpCode.twoByte(0x0f, 0x8c), | 1507 | .jna, |
| 1425 | .jge, .jnl => if (is_one_byte) OpCode.oneByte(0x7d) else OpCode.twoByte(0x0f, 0x8d), | 1508 | .jbe => if (is_one_byte) OpCode.init(&.{0x76}) else OpCode.init(&.{0x0f,0x86}), |
| 1426 | .jle, .jng => if (is_one_byte) OpCode.oneByte(0x7e) else OpCode.twoByte(0x0f, 0x8e), | 1509 | .jnbe, |
| 1427 | .jg, .jnle => if (is_one_byte) OpCode.oneByte(0x7f) else OpCode.twoByte(0x0f, 0x8f), | 1510 | .ja => if (is_one_byte) OpCode.init(&.{0x77}) else OpCode.init(&.{0x0f,0x87}), |
| 1428 | else => unreachable, | 1511 | .js => if (is_one_byte) OpCode.init(&.{0x78}) else OpCode.init(&.{0x0f,0x88}), |
| | 1512 | .jns => if (is_one_byte) OpCode.init(&.{0x79}) else OpCode.init(&.{0x0f,0x89}), |
| | 1513 | .jpe, |
| | 1514 | .jp => if (is_one_byte) OpCode.init(&.{0x7a}) else OpCode.init(&.{0x0f,0x8a}), |
| | 1515 | .jpo, |
| | 1516 | .jnp => if (is_one_byte) OpCode.init(&.{0x7b}) else OpCode.init(&.{0x0f,0x8b}), |
| | 1517 | .jnge, |
| | 1518 | .jl => if (is_one_byte) OpCode.init(&.{0x7c}) else OpCode.init(&.{0x0f,0x8c}), |
| | 1519 | .jge, |
| | 1520 | .jnl => if (is_one_byte) OpCode.init(&.{0x7d}) else OpCode.init(&.{0x0f,0x8d}), |
| | 1521 | .jle, |
| | 1522 | .jng => if (is_one_byte) OpCode.init(&.{0x7e}) else OpCode.init(&.{0x0f,0x8e}), |
| | 1523 | .jg, |
| | 1524 | .jnle => if (is_one_byte) OpCode.init(&.{0x7f}) else OpCode.init(&.{0x0f,0x8f}), |
| | 1525 | else => unreachable, |
| 1429 | }, | 1526 | }, |
| 1430 | .m => return switch (tag) { | 1527 | .m => return switch (tag) { |
| 1431 | .jmp_near, .call_near, .push => OpCode.oneByte(0xff), | 1528 | .jmp_near, |
| 1432 | .pop => OpCode.oneByte(0x8f), | 1529 | .call_near, |
| 1433 | .seto => OpCode.twoByte(0x0f, 0x90), | 1530 | .push => OpCode.init(&.{0xff}), |
| 1434 | .setno => OpCode.twoByte(0x0f, 0x91), | 1531 | .pop => OpCode.init(&.{0x8f}), |
| 1435 | .setb, .setc, .setnae => OpCode.twoByte(0x0f, 0x92), | 1532 | .seto => OpCode.init(&.{0x0f,0x90}), |
| 1436 | .setnb, .setnc, .setae => OpCode.twoByte(0x0f, 0x93), | 1533 | .setno => OpCode.init(&.{0x0f,0x91}), |
| 1437 | .sete, .setz => OpCode.twoByte(0x0f, 0x94), | 1534 | .setb, |
| 1438 | .setne, .setnz => OpCode.twoByte(0x0f, 0x95), | 1535 | .setc, |
| 1439 | .setbe, .setna => OpCode.twoByte(0x0f, 0x96), | 1536 | .setnae => OpCode.init(&.{0x0f,0x92}), |
| 1440 | .seta, .setnbe => OpCode.twoByte(0x0f, 0x97), | 1537 | .setnb, |
| 1441 | .sets => OpCode.twoByte(0x0f, 0x98), | 1538 | .setnc, |
| 1442 | .setns => OpCode.twoByte(0x0f, 0x99), | 1539 | .setae => OpCode.init(&.{0x0f,0x93}), |
| 1443 | .setp, .setpe => OpCode.twoByte(0x0f, 0x9a), | 1540 | .sete, |
| 1444 | .setnp, .setop => OpCode.twoByte(0x0f, 0x9b), | 1541 | .setz => OpCode.init(&.{0x0f,0x94}), |
| 1445 | .setl, .setnge => OpCode.twoByte(0x0f, 0x9c), | 1542 | .setne, |
| 1446 | .setnl, .setge => OpCode.twoByte(0x0f, 0x9d), | 1543 | .setnz => OpCode.init(&.{0x0f,0x95}), |
| 1447 | .setle, .setng => OpCode.twoByte(0x0f, 0x9e), | 1544 | .setbe, |
| 1448 | .setnle, .setg => OpCode.twoByte(0x0f, 0x9f), | 1545 | .setna => OpCode.init(&.{0x0f,0x96}), |
| 1449 | .idiv, .div, .imul, .mul => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7), | 1546 | .seta, |
| 1450 | .fisttp16 => OpCode.oneByte(0xdf), | 1547 | .setnbe => OpCode.init(&.{0x0f,0x97}), |
| 1451 | .fisttp32 => OpCode.oneByte(0xdb), | 1548 | .sets => OpCode.init(&.{0x0f,0x98}), |
| 1452 | .fisttp64 => OpCode.oneByte(0xdd), | 1549 | .setns => OpCode.init(&.{0x0f,0x99}), |
| 1453 | .fld32 => OpCode.oneByte(0xd9), | 1550 | .setp, |
| 1454 | .fld64 => OpCode.oneByte(0xdd), | 1551 | .setpe => OpCode.init(&.{0x0f,0x9a}), |
| 1455 | else => unreachable, | 1552 | .setnp, |
| | 1553 | .setop => OpCode.init(&.{0x0f,0x9b}), |
| | 1554 | .setl, |
| | 1555 | .setnge => OpCode.init(&.{0x0f,0x9c}), |
| | 1556 | .setnl, |
| | 1557 | .setge => OpCode.init(&.{0x0f,0x9d}), |
| | 1558 | .setle, |
| | 1559 | .setng => OpCode.init(&.{0x0f,0x9e}), |
| | 1560 | .setnle, |
| | 1561 | .setg => OpCode.init(&.{0x0f,0x9f}), |
| | 1562 | .idiv, |
| | 1563 | .div, |
| | 1564 | .imul, |
| | 1565 | .mul => if (is_one_byte) OpCode.init(&.{0xf6}) else OpCode.init(&.{0xf7}), |
| | 1566 | .fisttp16 => OpCode.init(&.{0xdf}), |
| | 1567 | .fisttp32 => OpCode.init(&.{0xdb}), |
| | 1568 | .fisttp64 => OpCode.init(&.{0xdd}), |
| | 1569 | .fld32 => OpCode.init(&.{0xd9}), |
| | 1570 | .fld64 => OpCode.init(&.{0xdd}), |
| | 1571 | else => unreachable, |
| 1456 | }, | 1572 | }, |
| 1457 | .o => return switch (tag) { | 1573 | .o => return switch (tag) { |
| 1458 | .push => OpCode.oneByte(0x50), | 1574 | .push => OpCode.init(&.{0x50}), |
| 1459 | .pop => OpCode.oneByte(0x58), | 1575 | .pop => OpCode.init(&.{0x58}), |
| 1460 | else => unreachable, | 1576 | else => unreachable, |
| 1461 | }, | 1577 | }, |
| 1462 | .i => return switch (tag) { | 1578 | .i => return switch (tag) { |
| 1463 | .push => OpCode.oneByte(if (is_one_byte) 0x6a else 0x68), | 1579 | .push => if (is_one_byte) OpCode.init(&.{0x6a}) else OpCode.init(&.{0x68}), |
| 1464 | .@"test" => OpCode.oneByte(if (is_one_byte) 0xa8 else 0xa9), | 1580 | .@"test" => if (is_one_byte) OpCode.init(&.{0xa8}) else OpCode.init(&.{0xa9}), |
| 1465 | .ret_near => OpCode.oneByte(0xc2), | 1581 | .ret_near => OpCode.init(&.{0xc2}), |
| 1466 | .ret_far => OpCode.oneByte(0xca), | 1582 | .ret_far => OpCode.init(&.{0xca}), |
| 1467 | else => unreachable, | 1583 | else => unreachable, |
| 1468 | }, | 1584 | }, |
| 1469 | .m1 => return switch (tag) { | 1585 | .m1 => return switch (tag) { |
| 1470 | .shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xd0 else 0xd1), | 1586 | .shl, .sal, |
| 1471 | else => unreachable, | 1587 | .shr, .sar => if (is_one_byte) OpCode.init(&.{0xd0}) else OpCode.init(&.{0xd1}), |
| | 1588 | else => unreachable, |
| 1472 | }, | 1589 | }, |
| 1473 | .mc => return switch (tag) { | 1590 | .mc => return switch (tag) { |
| 1474 | .shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xd2 else 0xd3), | 1591 | .shl, .sal, |
| 1475 | else => unreachable, | 1592 | .shr, .sar => if (is_one_byte) OpCode.init(&.{0xd2}) else OpCode.init(&.{0xd3}), |
| | 1593 | else => unreachable, |
| 1476 | }, | 1594 | }, |
| 1477 | .mi => return switch (tag) { | 1595 | .mi => return switch (tag) { |
| 1478 | .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => OpCode.oneByte(if (is_one_byte) 0x80 else 0x81), | 1596 | .adc, .add, |
| 1479 | .mov => OpCode.oneByte(if (is_one_byte) 0xc6 else 0xc7), | 1597 | .sub, .xor, |
| 1480 | .@"test" => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7), | 1598 | .@"and", .@"or", |
| 1481 | else => unreachable, | 1599 | .sbb, .cmp => if (is_one_byte) OpCode.init(&.{0x80}) else OpCode.init(&.{0x81}), |
| | 1600 | .mov => if (is_one_byte) OpCode.init(&.{0xc6}) else OpCode.init(&.{0xc7}), |
| | 1601 | .@"test" => if (is_one_byte) OpCode.init(&.{0xf6}) else OpCode.init(&.{0xf7}), |
| | 1602 | else => unreachable, |
| 1482 | }, | 1603 | }, |
| 1483 | .mi8 => return switch (tag) { | 1604 | .mi8 => return switch (tag) { |
| 1484 | .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => OpCode.oneByte(0x83), | 1605 | .adc, .add, |
| 1485 | .shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xc0 else 0xc1), | 1606 | .sub, .xor, |
| 1486 | else => unreachable, | 1607 | .@"and", .@"or", |
| | 1608 | .sbb, .cmp => OpCode.init(&.{0x83}), |
| | 1609 | .shl, .sal, |
| | 1610 | .shr, .sar => if (is_one_byte) OpCode.init(&.{0xc0}) else OpCode.init(&.{0xc1}), |
| | 1611 | else => unreachable, |
| 1487 | }, | 1612 | }, |
| 1488 | .mr => return switch (tag) { | 1613 | .mr => return switch (tag) { |
| 1489 | .adc => OpCode.oneByte(if (is_one_byte) 0x10 else 0x11), | 1614 | .adc => if (is_one_byte) OpCode.init(&.{0x10}) else OpCode.init(&.{0x11}), |
| 1490 | .add => OpCode.oneByte(if (is_one_byte) 0x00 else 0x01), | 1615 | .add => if (is_one_byte) OpCode.init(&.{0x00}) else OpCode.init(&.{0x01}), |
| 1491 | .sub => OpCode.oneByte(if (is_one_byte) 0x28 else 0x29), | 1616 | .sub => if (is_one_byte) OpCode.init(&.{0x28}) else OpCode.init(&.{0x29}), |
| 1492 | .xor => OpCode.oneByte(if (is_one_byte) 0x30 else 0x31), | 1617 | .xor => if (is_one_byte) OpCode.init(&.{0x30}) else OpCode.init(&.{0x31}), |
| 1493 | .@"and" => OpCode.oneByte(if (is_one_byte) 0x20 else 0x21), | 1618 | .@"and" => if (is_one_byte) OpCode.init(&.{0x20}) else OpCode.init(&.{0x21}), |
| 1494 | .@"or" => OpCode.oneByte(if (is_one_byte) 0x08 else 0x09), | 1619 | .@"or" => if (is_one_byte) OpCode.init(&.{0x08}) else OpCode.init(&.{0x09}), |
| 1495 | .sbb => OpCode.oneByte(if (is_one_byte) 0x18 else 0x19), | 1620 | .sbb => if (is_one_byte) OpCode.init(&.{0x18}) else OpCode.init(&.{0x19}), |
| 1496 | .cmp => OpCode.oneByte(if (is_one_byte) 0x38 else 0x39), | 1621 | .cmp => if (is_one_byte) OpCode.init(&.{0x38}) else OpCode.init(&.{0x39}), |
| 1497 | .mov => OpCode.oneByte(if (is_one_byte) 0x88 else 0x89), | 1622 | .mov => if (is_one_byte) OpCode.init(&.{0x88}) else OpCode.init(&.{0x89}), |
| 1498 | .@"test" => OpCode.oneByte(if (is_one_byte) 0x84 else 0x85), | 1623 | .@"test" => if (is_one_byte) OpCode.init(&.{0x84}) else OpCode.init(&.{0x85}), |
| 1499 | else => unreachable, | 1624 | .movsd => OpCode.init(&.{0xf2,0x0f,0x11}), |
| | 1625 | .movss => OpCode.init(&.{0xf3,0x0f,0x11}), |
| | 1626 | else => unreachable, |
| 1500 | }, | 1627 | }, |
| 1501 | .rm => return switch (tag) { | 1628 | .rm => return switch (tag) { |
| 1502 | .adc => OpCode.oneByte(if (is_one_byte) 0x12 else 0x13), | 1629 | .adc => if (is_one_byte) OpCode.init(&.{0x12}) else OpCode.init(&.{0x13}), |
| 1503 | .add => OpCode.oneByte(if (is_one_byte) 0x02 else 0x03), | 1630 | .add => if (is_one_byte) OpCode.init(&.{0x02}) else OpCode.init(&.{0x03}), |
| 1504 | .sub => OpCode.oneByte(if (is_one_byte) 0x2a else 0x2b), | 1631 | .sub => if (is_one_byte) OpCode.init(&.{0x2a}) else OpCode.init(&.{0x2b}), |
| 1505 | .xor => OpCode.oneByte(if (is_one_byte) 0x32 else 0x33), | 1632 | .xor => if (is_one_byte) OpCode.init(&.{0x32}) else OpCode.init(&.{0x33}), |
| 1506 | .@"and" => OpCode.oneByte(if (is_one_byte) 0x22 else 0x23), | 1633 | .@"and" => if (is_one_byte) OpCode.init(&.{0x22}) else OpCode.init(&.{0x23}), |
| 1507 | .@"or" => OpCode.oneByte(if (is_one_byte) 0x0a else 0x0b), | 1634 | .@"or" => if (is_one_byte) OpCode.init(&.{0x0a}) else OpCode.init(&.{0x0b}), |
| 1508 | .sbb => OpCode.oneByte(if (is_one_byte) 0x1a else 0x1b), | 1635 | .sbb => if (is_one_byte) OpCode.init(&.{0x1a}) else OpCode.init(&.{0x1b}), |
| 1509 | .cmp => OpCode.oneByte(if (is_one_byte) 0x3a else 0x3b), | 1636 | .cmp => if (is_one_byte) OpCode.init(&.{0x3a}) else OpCode.init(&.{0x3b}), |
| 1510 | .mov => OpCode.oneByte(if (is_one_byte) 0x8a else 0x8b), | 1637 | .mov => if (is_one_byte) OpCode.init(&.{0x8a}) else OpCode.init(&.{0x8b}), |
| 1511 | .movsx => OpCode.twoByte(0x0f, if (is_one_byte) 0xbe else 0xbf), | 1638 | .movsx => if (is_one_byte) OpCode.init(&.{0x0f,0xbe}) else OpCode.init(&.{0x0f,0xbf}), |
| 1512 | .movsxd => OpCode.oneByte(0x63), | 1639 | .movsxd => OpCode.init(&.{0x63}), |
| 1513 | .movzx => OpCode.twoByte(0x0f, if (is_one_byte) 0xb6 else 0xb7), | 1640 | .movzx => if (is_one_byte) OpCode.init(&.{0x0f,0xb6}) else OpCode.init(&.{0x0f,0xb7}), |
| 1514 | .lea => OpCode.oneByte(if (is_one_byte) 0x8c else 0x8d), | 1641 | .lea => if (is_one_byte) OpCode.init(&.{0x8c}) else OpCode.init(&.{0x8d}), |
| 1515 | .imul => OpCode.twoByte(0x0f, 0xaf), | 1642 | .imul => OpCode.init(&.{0x0f,0xaf}), |
| 1516 | .cmove, .cmovz => OpCode.twoByte(0x0f, 0x44), | 1643 | .cmove, |
| 1517 | .cmovb, .cmovnae => OpCode.twoByte(0x0f, 0x42), | 1644 | .cmovz => OpCode.init(&.{0x0f,0x44}), |
| 1518 | .cmovl, .cmovng => OpCode.twoByte(0x0f, 0x4c), | 1645 | .cmovb, |
| | 1646 | .cmovnae => OpCode.init(&.{0x0f,0x42}), |
| | 1647 | .cmovl, |
| | 1648 | .cmovng => OpCode.init(&.{0x0f,0x4c}), |
| | 1649 | .movsd => OpCode.init(&.{0xf2,0x0f,0x10}), |
| | 1650 | .movss => OpCode.init(&.{0xf3,0x0f,0x10}), |
| | 1651 | .addsd => OpCode.init(&.{0xf2,0x0f,0x58}), |
| | 1652 | .addss => OpCode.init(&.{0xf3,0x0f,0x58}), |
| | 1653 | .ucomisd => OpCode.init(&.{0x66,0x0f,0x2e}), |
| | 1654 | .ucomiss => OpCode.init(&.{0x0f,0x2e}), |
| 1519 | else => unreachable, | 1655 | else => unreachable, |
| 1520 | }, | 1656 | }, |
| 1521 | .oi => return switch (tag) { | 1657 | .oi => return switch (tag) { |
| 1522 | .mov => OpCode.oneByte(if (is_one_byte) 0xb0 else 0xb8), | 1658 | .mov => if (is_one_byte) OpCode.init(&.{0xb0}) else OpCode.init(&.{0xb8}), |
| 1523 | else => unreachable, | 1659 | else => unreachable, |
| 1524 | }, | 1660 | }, |
| 1525 | .fd => return switch (tag) { | 1661 | .fd => return switch (tag) { |
| 1526 | .mov => OpCode.oneByte(if (is_one_byte) 0xa0 else 0xa1), | 1662 | .mov => if (is_one_byte) OpCode.init(&.{0xa0}) else OpCode.init(&.{0xa1}), |
| 1527 | else => unreachable, | 1663 | else => unreachable, |
| 1528 | }, | 1664 | }, |
| 1529 | .td => return switch (tag) { | 1665 | .td => return switch (tag) { |
| 1530 | .mov => OpCode.oneByte(if (is_one_byte) 0xa2 else 0xa3), | 1666 | .mov => if (is_one_byte) OpCode.init(&.{0xa2}) else OpCode.init(&.{0xa3}), |
| 1531 | else => unreachable, | 1667 | else => unreachable, |
| 1532 | }, | 1668 | }, |
| 1533 | .rmi => return switch (tag) { | 1669 | .rmi => return switch (tag) { |
| 1534 | .imul => OpCode.oneByte(if (is_one_byte) 0x6b else 0x69), | 1670 | .imul => if (is_one_byte) OpCode.init(&.{0x6b}) else OpCode.init(&.{0x69}), |
| 1535 | else => unreachable, | 1671 | else => unreachable, |
| 1536 | }, | 1672 | }, |
| 1537 | .mv => return switch (tag) { | 1673 | .mv => return switch (tag) { |
| 1538 | .vmovsd, .vmovss => OpCode.oneByte(0x11), | 1674 | .vmovsd, |
| | 1675 | .vmovss => OpCode.init(&.{0x11}), |
| 1539 | else => unreachable, | 1676 | else => unreachable, |
| 1540 | }, | 1677 | }, |
| 1541 | .vm => return switch (tag) { | 1678 | .vm => return switch (tag) { |
| 1542 | .vmovsd, .vmovss => OpCode.oneByte(0x10), | 1679 | .vmovsd, |
| 1543 | .vucomisd, .vucomiss => OpCode.oneByte(0x2e), | 1680 | .vmovss => OpCode.init(&.{0x10}), |
| | 1681 | .vucomisd, |
| | 1682 | .vucomiss => OpCode.init(&.{0x2e}), |
| 1544 | else => unreachable, | 1683 | else => unreachable, |
| 1545 | }, | 1684 | }, |
| 1546 | .rvm => return switch (tag) { | 1685 | .rvm => return switch (tag) { |
| 1547 | .vaddsd, .vaddss => OpCode.oneByte(0x58), | 1686 | .vaddsd, |
| 1548 | .vmovsd, .vmovss => OpCode.oneByte(0x10), | 1687 | .vaddss => OpCode.init(&.{0x58}), |
| | 1688 | .vmovsd, |
| | 1689 | .vmovss => OpCode.init(&.{0x10}), |
| 1549 | else => unreachable, | 1690 | else => unreachable, |
| 1550 | }, | 1691 | }, |
| 1551 | .rvmi => return switch (tag) { | 1692 | .rvmi => return switch (tag) { |
| 1552 | .vcmpsd, .vcmpss => OpCode.oneByte(0xc2), | 1693 | .vcmpsd, |
| 1553 | else => unreachable, | 1694 | .vcmpss => OpCode.init(&.{0xc2}), |
| | 1695 | else => unreachable, |
| 1554 | }, | 1696 | }, |
| 1555 | } | 1697 | } |
| | 1698 | // zig fmt: on |
| 1556 | } | 1699 | } |
| 1557 | | 1700 | |
| 1558 | inline fn getModRmExt(tag: Tag) u3 { | 1701 | inline fn getModRmExt(tag: Tag) u3 { |