authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-05-08 19:04:05+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-05-08 19:04:05+02:00
logf40539e5d83365412bf8c6973ce867125ea36faf
treec8b6c458a2a20c1846d57721de33d2befed750e7
parent16314e0e199051289075c9e3dab425ce3fb52719
parent1f5aa7747f5710e281cd2190508ce562a4bfd35f
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #15597 from jacobly0/x86_64-behavior

x86_64: more behavior than ever before

18 files changed, 4760 insertions(+), 2753 deletions(-)

lib/std/target/x86.zig+3-3
......@@ -326,7 +326,7 @@ pub const all_features = blk: {
326326 };
327327 result[@enumToInt(Feature.avx512ifma)] = .{
328328 .llvm_name = "avx512ifma",
329 .description = "Enable AVX-512 Integer Fused Multiple-Add",
329 .description = "Enable AVX-512 Integer Fused Multiply-Add",
330330 .dependencies = featureSet(&[_]Feature{
331331 .avx512f,
332332 }),
......@@ -599,14 +599,14 @@ pub const all_features = blk: {
599599 };
600600 result[@enumToInt(Feature.fma)] = .{
601601 .llvm_name = "fma",
602 .description = "Enable three-operand fused multiple-add",
602 .description = "Enable three-operand fused multiply-add",
603603 .dependencies = featureSet(&[_]Feature{
604604 .avx,
605605 }),
606606 };
607607 result[@enumToInt(Feature.fma4)] = .{
608608 .llvm_name = "fma4",
609 .description = "Enable four-operand fused multiple-add",
609 .description = "Enable four-operand fused multiply-add",
610610 .dependencies = featureSet(&[_]Feature{
611611 .avx,
612612 .sse4a,
src/arch/x86_64/CodeGen.zig+2140-944
......@@ -205,16 +205,7 @@ pub const MCValue = union(enum) {
205205
206206 fn isMemory(mcv: MCValue) bool {
207207 return switch (mcv) {
208 .memory,
209 .load_direct,
210 .lea_direct,
211 .load_got,
212 .lea_got,
213 .load_tlv,
214 .lea_tlv,
215 .load_frame,
216 .lea_frame,
217 => true,
208 .memory, .indirect, .load_frame => true,
218209 else => false,
219210 };
220211 }
......@@ -937,7 +928,7 @@ fn formatWipMir(
937928 .target = data.self.target,
938929 .src_loc = data.self.src_loc,
939930 };
940 for (lower.lowerMir(data.self.mir_instructions.get(data.inst)) catch |err| switch (err) {
931 for ((lower.lowerMir(data.inst) catch |err| switch (err) {
941932 error.LowerFail => {
942933 defer {
943934 lower.err_msg.?.deinit(data.self.gpa);
......@@ -955,7 +946,7 @@ fn formatWipMir(
955946 return;
956947 },
957948 else => |e| return e,
958 }) |lower_inst| try writer.print(" | {}", .{lower_inst});
949 }).insts) |lowered_inst| try writer.print(" | {}", .{lowered_inst});
959950}
960951fn fmtWipMir(self: *Self, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir) {
961952 return .{ .data = .{ .self = self, .inst = inst } };
......@@ -982,14 +973,14 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
982973 try self.mir_instructions.ensureUnusedCapacity(gpa, 1);
983974 const result_index = @intCast(Mir.Inst.Index, self.mir_instructions.len);
984975 self.mir_instructions.appendAssumeCapacity(inst);
985 switch (inst.tag) {
986 else => wip_mir_log.debug("{}", .{self.fmtWipMir(result_index)}),
987 .dbg_line,
988 .dbg_prologue_end,
989 .dbg_epilogue_begin,
990 .dead,
991 => {},
992 }
976 if (inst.tag != .pseudo or switch (inst.ops) {
977 else => true,
978 .pseudo_dbg_prologue_end_none,
979 .pseudo_dbg_line_line_column,
980 .pseudo_dbg_epilogue_begin_none,
981 .pseudo_dead_none,
982 => false,
983 }) wip_mir_log.debug("{}", .{self.fmtWipMir(result_index)});
993984 return result_index;
994985}
995986
......@@ -1012,131 +1003,248 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
10121003 return result;
10131004}
10141005
1015fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void {
1006/// A `cc` of `.z_and_np` clobbers `reg2`!
1007fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bits.Condition) !void {
10161008 _ = try self.addInst(.{
1017 .tag = .setcc,
1018 .ops = .r_cc,
1019 .data = .{ .r_cc = .{ .r = reg, .cc = cc } },
1009 .tag = switch (cc) {
1010 else => .cmov,
1011 .z_and_np, .nz_or_p => .pseudo,
1012 },
1013 .ops = switch (cc) {
1014 else => .rr,
1015 .z_and_np => .pseudo_cmov_z_and_np_rr,
1016 .nz_or_p => .pseudo_cmov_nz_or_p_rr,
1017 },
1018 .data = .{ .rr = .{
1019 .fixes = switch (cc) {
1020 else => Mir.Inst.Fixes.fromCondition(cc),
1021 .z_and_np, .nz_or_p => ._,
1022 },
1023 .r1 = reg1,
1024 .r2 = reg2,
1025 } },
10201026 });
10211027}
10221028
1023fn asmSetccMemory(self: *Self, m: Memory, cc: bits.Condition) !void {
1029/// A `cc` of `.z_and_np` is not supported by this encoding!
1030fn asmCmovccRegisterMemory(self: *Self, reg: Register, m: Memory, cc: bits.Condition) !void {
10241031 _ = try self.addInst(.{
1025 .tag = .setcc,
1026 .ops = switch (m) {
1027 .sib => .m_sib_cc,
1028 .rip => .m_rip_cc,
1029 else => unreachable,
1032 .tag = switch (cc) {
1033 else => .cmov,
1034 .z_and_np => unreachable,
1035 .nz_or_p => .pseudo,
10301036 },
1031 .data = .{ .x_cc = .{ .cc = cc, .payload = switch (m) {
1032 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1033 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1034 else => unreachable,
1035 } } },
1037 .ops = switch (cc) {
1038 else => switch (m) {
1039 .sib => .rm_sib,
1040 .rip => .rm_rip,
1041 else => unreachable,
1042 },
1043 .z_and_np => unreachable,
1044 .nz_or_p => switch (m) {
1045 .sib => .pseudo_cmov_nz_or_p_rm_sib,
1046 .rip => .pseudo_cmov_nz_or_p_rm_rip,
1047 else => unreachable,
1048 },
1049 },
1050 .data = .{ .rx = .{
1051 .fixes = switch (cc) {
1052 else => Mir.Inst.Fixes.fromCondition(cc),
1053 .z_and_np => unreachable,
1054 .nz_or_p => ._,
1055 },
1056 .r1 = reg,
1057 .payload = switch (m) {
1058 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1059 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1060 else => unreachable,
1061 },
1062 } },
10361063 });
10371064}
10381065
1039fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bits.Condition) !void {
1066fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void {
10401067 _ = try self.addInst(.{
1041 .tag = .cmovcc,
1042 .ops = .rr_cc,
1043 .data = .{ .rr_cc = .{ .r1 = reg1, .r2 = reg2, .cc = cc } },
1068 .tag = switch (cc) {
1069 else => .set,
1070 .z_and_np, .nz_or_p => .pseudo,
1071 },
1072 .ops = switch (cc) {
1073 else => .r,
1074 .z_and_np => .pseudo_set_z_and_np_r,
1075 .nz_or_p => .pseudo_set_nz_or_p_r,
1076 },
1077 .data = switch (cc) {
1078 else => .{ .r = .{
1079 .fixes = Mir.Inst.Fixes.fromCondition(cc),
1080 .r1 = reg,
1081 } },
1082 .z_and_np, .nz_or_p => .{ .r_scratch = .{
1083 .r1 = reg,
1084 .scratch_reg = (try self.register_manager.allocReg(null, gp)).to8(),
1085 } },
1086 },
10441087 });
10451088}
10461089
1047fn asmCmovccRegisterMemory(self: *Self, reg: Register, m: Memory, cc: bits.Condition) !void {
1090fn asmSetccMemory(self: *Self, m: Memory, cc: bits.Condition) !void {
1091 const payload = switch (m) {
1092 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1093 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1094 else => unreachable,
1095 };
10481096 _ = try self.addInst(.{
1049 .tag = .cmovcc,
1050 .ops = switch (m) {
1051 .sib => .rm_sib_cc,
1052 .rip => .rm_rip_cc,
1053 else => unreachable,
1097 .tag = switch (cc) {
1098 else => .set,
1099 .z_and_np, .nz_or_p => .pseudo,
1100 },
1101 .ops = switch (cc) {
1102 else => switch (m) {
1103 .sib => .m_sib,
1104 .rip => .m_rip,
1105 else => unreachable,
1106 },
1107 .z_and_np => switch (m) {
1108 .sib => .pseudo_set_z_and_np_m_sib,
1109 .rip => .pseudo_set_z_and_np_m_rip,
1110 else => unreachable,
1111 },
1112 .nz_or_p => switch (m) {
1113 .sib => .pseudo_set_nz_or_p_m_sib,
1114 .rip => .pseudo_set_nz_or_p_m_rip,
1115 else => unreachable,
1116 },
1117 },
1118 .data = switch (cc) {
1119 else => .{ .x = .{
1120 .fixes = Mir.Inst.Fixes.fromCondition(cc),
1121 .payload = payload,
1122 } },
1123 .z_and_np, .nz_or_p => .{ .x_scratch = .{
1124 .scratch_reg = (try self.register_manager.allocReg(null, gp)).to8(),
1125 .payload = payload,
1126 } },
10541127 },
1055 .data = .{ .rx_cc = .{ .r = reg, .cc = cc, .payload = switch (m) {
1056 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1057 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1058 else => unreachable,
1059 } } },
10601128 });
10611129}
10621130
10631131fn asmJmpReloc(self: *Self, target: Mir.Inst.Index) !Mir.Inst.Index {
10641132 return self.addInst(.{
1065 .tag = .jmp_reloc,
1066 .ops = undefined,
1067 .data = .{ .inst = target },
1133 .tag = .jmp,
1134 .ops = .inst,
1135 .data = .{ .inst = .{
1136 .inst = target,
1137 } },
10681138 });
10691139}
10701140
10711141fn asmJccReloc(self: *Self, target: Mir.Inst.Index, cc: bits.Condition) !Mir.Inst.Index {
10721142 return self.addInst(.{
1073 .tag = .jcc,
1074 .ops = .inst_cc,
1075 .data = .{ .inst_cc = .{ .inst = target, .cc = cc } },
1143 .tag = switch (cc) {
1144 else => .j,
1145 .z_and_np, .nz_or_p => .pseudo,
1146 },
1147 .ops = switch (cc) {
1148 else => .inst,
1149 .z_and_np => .pseudo_j_z_and_np_inst,
1150 .nz_or_p => .pseudo_j_nz_or_p_inst,
1151 },
1152 .data = .{ .inst = .{
1153 .fixes = switch (cc) {
1154 else => Mir.Inst.Fixes.fromCondition(cc),
1155 .z_and_np, .nz_or_p => ._,
1156 },
1157 .inst = target,
1158 } },
10761159 });
10771160}
10781161
10791162fn asmPlaceholder(self: *Self) !Mir.Inst.Index {
10801163 return self.addInst(.{
1081 .tag = .dead,
1082 .ops = undefined,
1164 .tag = .pseudo,
1165 .ops = .pseudo_dead_none,
10831166 .data = undefined,
10841167 });
10851168}
10861169
1087fn asmOpOnly(self: *Self, tag: Mir.Inst.Tag) !void {
1170fn asmOpOnly(self: *Self, tag: Mir.Inst.FixedTag) !void {
10881171 _ = try self.addInst(.{
1089 .tag = tag,
1172 .tag = tag[1],
10901173 .ops = .none,
1174 .data = .{ .none = .{
1175 .fixes = tag[0],
1176 } },
1177 });
1178}
1179
1180fn asmPseudo(self: *Self, ops: Mir.Inst.Ops) !void {
1181 _ = try self.addInst(.{
1182 .tag = .pseudo,
1183 .ops = ops,
10911184 .data = undefined,
10921185 });
10931186}
10941187
1095fn asmRegister(self: *Self, tag: Mir.Inst.Tag, reg: Register) !void {
1188fn asmRegister(self: *Self, tag: Mir.Inst.FixedTag, reg: Register) !void {
10961189 _ = try self.addInst(.{
1097 .tag = tag,
1190 .tag = tag[1],
10981191 .ops = .r,
1099 .data = .{ .r = reg },
1192 .data = .{ .r = .{
1193 .fixes = tag[0],
1194 .r1 = reg,
1195 } },
11001196 });
11011197}
11021198
1103fn asmImmediate(self: *Self, tag: Mir.Inst.Tag, imm: Immediate) !void {
1199fn asmImmediate(self: *Self, tag: Mir.Inst.FixedTag, imm: Immediate) !void {
11041200 _ = try self.addInst(.{
1105 .tag = tag,
1201 .tag = tag[1],
11061202 .ops = switch (imm) {
11071203 .signed => .i_s,
11081204 .unsigned => .i_u,
11091205 },
1110 .data = .{ .i = switch (imm) {
1111 .signed => |s| @bitCast(u32, s),
1112 .unsigned => |u| @intCast(u32, u),
1206 .data = .{ .i = .{
1207 .fixes = tag[0],
1208 .i = switch (imm) {
1209 .signed => |s| @bitCast(u32, s),
1210 .unsigned => |u| @intCast(u32, u),
1211 },
11131212 } },
11141213 });
11151214}
11161215
1117fn asmRegisterRegister(self: *Self, tag: Mir.Inst.Tag, reg1: Register, reg2: Register) !void {
1216fn asmRegisterRegister(self: *Self, tag: Mir.Inst.FixedTag, reg1: Register, reg2: Register) !void {
11181217 _ = try self.addInst(.{
1119 .tag = tag,
1218 .tag = tag[1],
11201219 .ops = .rr,
1121 .data = .{ .rr = .{ .r1 = reg1, .r2 = reg2 } },
1220 .data = .{ .rr = .{
1221 .fixes = tag[0],
1222 .r1 = reg1,
1223 .r2 = reg2,
1224 } },
11221225 });
11231226}
11241227
1125fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Immediate) !void {
1228fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, imm: Immediate) !void {
11261229 const ops: Mir.Inst.Ops = switch (imm) {
11271230 .signed => .ri_s,
11281231 .unsigned => |u| if (math.cast(u32, u)) |_| .ri_u else .ri64,
11291232 };
11301233 _ = try self.addInst(.{
1131 .tag = tag,
1234 .tag = tag[1],
11321235 .ops = ops,
11331236 .data = switch (ops) {
1134 .ri_s, .ri_u => .{ .ri = .{ .r = reg, .i = switch (imm) {
1135 .signed => |s| @bitCast(u32, s),
1136 .unsigned => |u| @intCast(u32, u),
1137 } } },
1237 .ri_s, .ri_u => .{ .ri = .{
1238 .fixes = tag[0],
1239 .r1 = reg,
1240 .i = switch (imm) {
1241 .signed => |s| @bitCast(u32, s),
1242 .unsigned => |u| @intCast(u32, u),
1243 },
1244 } },
11381245 .ri64 => .{ .rx = .{
1139 .r = reg,
1246 .fixes = tag[0],
1247 .r1 = reg,
11401248 .payload = try self.addExtra(Mir.Imm64.encode(imm.unsigned)),
11411249 } },
11421250 else => unreachable,
......@@ -1146,111 +1254,214 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Imme
11461254
11471255fn asmRegisterRegisterRegister(
11481256 self: *Self,
1149 tag: Mir.Inst.Tag,
1257 tag: Mir.Inst.FixedTag,
11501258 reg1: Register,
11511259 reg2: Register,
11521260 reg3: Register,
11531261) !void {
11541262 _ = try self.addInst(.{
1155 .tag = tag,
1263 .tag = tag[1],
11561264 .ops = .rrr,
1157 .data = .{ .rrr = .{ .r1 = reg1, .r2 = reg2, .r3 = reg3 } },
1265 .data = .{ .rrr = .{
1266 .fixes = tag[0],
1267 .r1 = reg1,
1268 .r2 = reg2,
1269 .r3 = reg3,
1270 } },
1271 });
1272}
1273
1274fn asmRegisterRegisterRegisterImmediate(
1275 self: *Self,
1276 tag: Mir.Inst.FixedTag,
1277 reg1: Register,
1278 reg2: Register,
1279 reg3: Register,
1280 imm: Immediate,
1281) !void {
1282 _ = try self.addInst(.{
1283 .tag = tag[1],
1284 .ops = .rrri,
1285 .data = .{ .rrri = .{
1286 .fixes = tag[0],
1287 .r1 = reg1,
1288 .r2 = reg2,
1289 .r3 = reg3,
1290 .i = @intCast(u8, imm.unsigned),
1291 } },
11581292 });
11591293}
11601294
11611295fn asmRegisterRegisterImmediate(
11621296 self: *Self,
1163 tag: Mir.Inst.Tag,
1297 tag: Mir.Inst.FixedTag,
11641298 reg1: Register,
11651299 reg2: Register,
11661300 imm: Immediate,
11671301) !void {
11681302 _ = try self.addInst(.{
1169 .tag = tag,
1303 .tag = tag[1],
11701304 .ops = switch (imm) {
11711305 .signed => .rri_s,
11721306 .unsigned => .rri_u,
11731307 },
1174 .data = .{ .rri = .{ .r1 = reg1, .r2 = reg2, .i = switch (imm) {
1175 .signed => |s| @bitCast(u32, s),
1176 .unsigned => |u| @intCast(u32, u),
1177 } } },
1308 .data = .{ .rri = .{
1309 .fixes = tag[0],
1310 .r1 = reg1,
1311 .r2 = reg2,
1312 .i = switch (imm) {
1313 .signed => |s| @bitCast(u32, s),
1314 .unsigned => |u| @intCast(u32, u),
1315 },
1316 } },
1317 });
1318}
1319
1320fn asmRegisterRegisterMemory(
1321 self: *Self,
1322 tag: Mir.Inst.FixedTag,
1323 reg1: Register,
1324 reg2: Register,
1325 m: Memory,
1326) !void {
1327 _ = try self.addInst(.{
1328 .tag = tag[1],
1329 .ops = switch (m) {
1330 .sib => .rrm_sib,
1331 .rip => .rrm_rip,
1332 else => unreachable,
1333 },
1334 .data = .{ .rrx = .{
1335 .fixes = tag[0],
1336 .r1 = reg1,
1337 .r2 = reg2,
1338 .payload = switch (m) {
1339 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1340 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1341 else => unreachable,
1342 },
1343 } },
11781344 });
11791345}
11801346
1181fn asmMemory(self: *Self, tag: Mir.Inst.Tag, m: Memory) !void {
1347fn asmMemory(self: *Self, tag: Mir.Inst.FixedTag, m: Memory) !void {
11821348 _ = try self.addInst(.{
1183 .tag = tag,
1349 .tag = tag[1],
11841350 .ops = switch (m) {
11851351 .sib => .m_sib,
11861352 .rip => .m_rip,
11871353 else => unreachable,
11881354 },
1189 .data = .{ .payload = switch (m) {
1190 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1191 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1192 else => unreachable,
1355 .data = .{ .x = .{
1356 .fixes = tag[0],
1357 .payload = switch (m) {
1358 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1359 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1360 else => unreachable,
1361 },
11931362 } },
11941363 });
11951364}
11961365
1197fn asmRegisterMemory(self: *Self, tag: Mir.Inst.Tag, reg: Register, m: Memory) !void {
1366fn asmRegisterMemory(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, m: Memory) !void {
11981367 _ = try self.addInst(.{
1199 .tag = tag,
1368 .tag = tag[1],
12001369 .ops = switch (m) {
12011370 .sib => .rm_sib,
12021371 .rip => .rm_rip,
12031372 else => unreachable,
12041373 },
1205 .data = .{ .rx = .{ .r = reg, .payload = switch (m) {
1206 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1207 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1208 else => unreachable,
1209 } } },
1374 .data = .{ .rx = .{
1375 .fixes = tag[0],
1376 .r1 = reg,
1377 .payload = switch (m) {
1378 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1379 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1380 else => unreachable,
1381 },
1382 } },
12101383 });
12111384}
12121385
12131386fn asmRegisterMemoryImmediate(
12141387 self: *Self,
1215 tag: Mir.Inst.Tag,
1388 tag: Mir.Inst.FixedTag,
12161389 reg: Register,
12171390 m: Memory,
12181391 imm: Immediate,
12191392) !void {
12201393 _ = try self.addInst(.{
1221 .tag = tag,
1394 .tag = tag[1],
12221395 .ops = switch (m) {
12231396 .sib => .rmi_sib,
12241397 .rip => .rmi_rip,
12251398 else => unreachable,
12261399 },
1227 .data = .{ .rix = .{ .r = reg, .i = @intCast(u8, imm.unsigned), .payload = switch (m) {
1228 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1229 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1400 .data = .{ .rix = .{
1401 .fixes = tag[0],
1402 .r1 = reg,
1403 .i = @intCast(u8, imm.unsigned),
1404 .payload = switch (m) {
1405 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1406 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1407 else => unreachable,
1408 },
1409 } },
1410 });
1411}
1412
1413fn asmRegisterRegisterMemoryImmediate(
1414 self: *Self,
1415 tag: Mir.Inst.FixedTag,
1416 reg1: Register,
1417 reg2: Register,
1418 m: Memory,
1419 imm: Immediate,
1420) !void {
1421 _ = try self.addInst(.{
1422 .tag = tag[1],
1423 .ops = switch (m) {
1424 .sib => .rrmi_sib,
1425 .rip => .rrmi_rip,
12301426 else => unreachable,
1231 } } },
1427 },
1428 .data = .{ .rrix = .{
1429 .fixes = tag[0],
1430 .r1 = reg1,
1431 .r2 = reg2,
1432 .i = @intCast(u8, imm.unsigned),
1433 .payload = switch (m) {
1434 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1435 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1436 else => unreachable,
1437 },
1438 } },
12321439 });
12331440}
12341441
1235fn asmMemoryRegister(self: *Self, tag: Mir.Inst.Tag, m: Memory, reg: Register) !void {
1442fn asmMemoryRegister(self: *Self, tag: Mir.Inst.FixedTag, m: Memory, reg: Register) !void {
12361443 _ = try self.addInst(.{
1237 .tag = tag,
1444 .tag = tag[1],
12381445 .ops = switch (m) {
12391446 .sib => .mr_sib,
12401447 .rip => .mr_rip,
12411448 else => unreachable,
12421449 },
1243 .data = .{ .rx = .{ .r = reg, .payload = switch (m) {
1244 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1245 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1246 else => unreachable,
1247 } } },
1450 .data = .{ .rx = .{
1451 .fixes = tag[0],
1452 .r1 = reg,
1453 .payload = switch (m) {
1454 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1455 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1456 else => unreachable,
1457 },
1458 } },
12481459 });
12491460}
12501461
1251fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.Tag, m: Memory, imm: Immediate) !void {
1462fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.FixedTag, m: Memory, imm: Immediate) !void {
12521463 _ = try self.addInst(.{
1253 .tag = tag,
1464 .tag = tag[1],
12541465 .ops = switch (m) {
12551466 .sib => switch (imm) {
12561467 .signed => .mi_sib_s,
......@@ -1262,67 +1473,81 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.Tag, m: Memory, imm: Immediate)
12621473 },
12631474 else => unreachable,
12641475 },
1265 .data = .{ .ix = .{ .i = switch (imm) {
1266 .signed => |s| @bitCast(u32, s),
1267 .unsigned => |u| @intCast(u32, u),
1268 }, .payload = switch (m) {
1269 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1270 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1271 else => unreachable,
1272 } } },
1476 .data = .{ .x = .{
1477 .fixes = tag[0],
1478 .payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) {
1479 .signed => |s| @bitCast(u32, s),
1480 .unsigned => |u| @intCast(u32, u),
1481 } }),
1482 } },
12731483 });
1484 _ = switch (m) {
1485 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1486 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1487 else => unreachable,
1488 };
12741489}
12751490
12761491fn asmMemoryRegisterRegister(
12771492 self: *Self,
1278 tag: Mir.Inst.Tag,
1493 tag: Mir.Inst.FixedTag,
12791494 m: Memory,
12801495 reg1: Register,
12811496 reg2: Register,
12821497) !void {
12831498 _ = try self.addInst(.{
1284 .tag = tag,
1499 .tag = tag[1],
12851500 .ops = switch (m) {
12861501 .sib => .mrr_sib,
12871502 .rip => .mrr_rip,
12881503 else => unreachable,
12891504 },
1290 .data = .{ .rrx = .{ .r1 = reg1, .r2 = reg2, .payload = switch (m) {
1291 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1292 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1293 else => unreachable,
1294 } } },
1505 .data = .{ .rrx = .{
1506 .fixes = tag[0],
1507 .r1 = reg1,
1508 .r2 = reg2,
1509 .payload = switch (m) {
1510 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1511 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1512 else => unreachable,
1513 },
1514 } },
12951515 });
12961516}
12971517
12981518fn asmMemoryRegisterImmediate(
12991519 self: *Self,
1300 tag: Mir.Inst.Tag,
1520 tag: Mir.Inst.FixedTag,
13011521 m: Memory,
13021522 reg: Register,
13031523 imm: Immediate,
13041524) !void {
13051525 _ = try self.addInst(.{
1306 .tag = tag,
1526 .tag = tag[1],
13071527 .ops = switch (m) {
13081528 .sib => .mri_sib,
13091529 .rip => .mri_rip,
13101530 else => unreachable,
13111531 },
1312 .data = .{ .rix = .{ .r = reg, .i = @intCast(u8, imm.unsigned), .payload = switch (m) {
1313 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1314 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1315 else => unreachable,
1316 } } },
1532 .data = .{ .rix = .{
1533 .fixes = tag[0],
1534 .r1 = reg,
1535 .i = @intCast(u8, imm.unsigned),
1536 .payload = switch (m) {
1537 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1538 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1539 else => unreachable,
1540 },
1541 } },
13171542 });
13181543}
13191544
13201545fn gen(self: *Self) InnerError!void {
13211546 const cc = self.fn_type.fnCallingConvention();
13221547 if (cc != .Naked) {
1323 try self.asmRegister(.push, .rbp);
1548 try self.asmRegister(.{ ._, .push }, .rbp);
13241549 const backpatch_push_callee_preserved_regs = try self.asmPlaceholder();
1325 try self.asmRegisterRegister(.mov, .rbp, .rsp);
1550 try self.asmRegisterRegister(.{ ._, .mov }, .rbp, .rsp);
13261551 const backpatch_frame_align = try self.asmPlaceholder();
13271552 const backpatch_stack_alloc = try self.asmPlaceholder();
13281553
......@@ -1346,7 +1571,7 @@ fn gen(self: *Self) InnerError!void {
13461571 else => unreachable,
13471572 }
13481573
1349 try self.asmOpOnly(.dbg_prologue_end);
1574 try self.asmPseudo(.pseudo_dbg_prologue_end_none);
13501575
13511576 try self.genBody(self.air.getMainBody());
13521577
......@@ -1358,15 +1583,15 @@ fn gen(self: *Self) InnerError!void {
13581583 // }
13591584 // Eliding the reloc will cause a miscompilation in this case.
13601585 for (self.exitlude_jump_relocs.items) |jmp_reloc| {
1361 self.mir_instructions.items(.data)[jmp_reloc].inst =
1586 self.mir_instructions.items(.data)[jmp_reloc].inst.inst =
13621587 @intCast(u32, self.mir_instructions.len);
13631588 }
13641589
1365 try self.asmOpOnly(.dbg_epilogue_begin);
1590 try self.asmPseudo(.pseudo_dbg_epilogue_begin_none);
13661591 const backpatch_stack_dealloc = try self.asmPlaceholder();
13671592 const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder();
1368 try self.asmRegister(.pop, .rbp);
1369 try self.asmOpOnly(.ret);
1593 try self.asmRegister(.{ ._, .pop }, .rbp);
1594 try self.asmOpOnly(.{ ._, .ret });
13701595
13711596 const frame_layout = try self.computeFrameLayout();
13721597 const need_frame_align = frame_layout.stack_mask != math.maxInt(u32);
......@@ -1376,46 +1601,54 @@ fn gen(self: *Self) InnerError!void {
13761601 self.mir_instructions.set(backpatch_frame_align, .{
13771602 .tag = .@"and",
13781603 .ops = .ri_s,
1379 .data = .{ .ri = .{ .r = .rsp, .i = frame_layout.stack_mask } },
1604 .data = .{ .ri = .{
1605 .r1 = .rsp,
1606 .i = frame_layout.stack_mask,
1607 } },
13801608 });
13811609 }
13821610 if (need_stack_adjust) {
13831611 self.mir_instructions.set(backpatch_stack_alloc, .{
13841612 .tag = .sub,
13851613 .ops = .ri_s,
1386 .data = .{ .ri = .{ .r = .rsp, .i = frame_layout.stack_adjust } },
1614 .data = .{ .ri = .{
1615 .r1 = .rsp,
1616 .i = frame_layout.stack_adjust,
1617 } },
13871618 });
13881619 }
13891620 if (need_frame_align or need_stack_adjust) {
13901621 self.mir_instructions.set(backpatch_stack_dealloc, .{
13911622 .tag = .mov,
13921623 .ops = .rr,
1393 .data = .{ .rr = .{ .r1 = .rsp, .r2 = .rbp } },
1624 .data = .{ .rr = .{
1625 .r1 = .rsp,
1626 .r2 = .rbp,
1627 } },
13941628 });
13951629 }
13961630 if (need_save_reg) {
1397 const save_reg_list = frame_layout.save_reg_list.asInt();
13981631 self.mir_instructions.set(backpatch_push_callee_preserved_regs, .{
1399 .tag = .push_regs,
1400 .ops = undefined,
1401 .data = .{ .payload = save_reg_list },
1632 .tag = .pseudo,
1633 .ops = .pseudo_push_reg_list,
1634 .data = .{ .reg_list = frame_layout.save_reg_list },
14021635 });
14031636 self.mir_instructions.set(backpatch_pop_callee_preserved_regs, .{
1404 .tag = .pop_regs,
1405 .ops = undefined,
1406 .data = .{ .payload = save_reg_list },
1637 .tag = .pseudo,
1638 .ops = .pseudo_pop_reg_list,
1639 .data = .{ .reg_list = frame_layout.save_reg_list },
14071640 });
14081641 }
14091642 } else {
1410 try self.asmOpOnly(.dbg_prologue_end);
1643 try self.asmPseudo(.pseudo_dbg_prologue_end_none);
14111644 try self.genBody(self.air.getMainBody());
1412 try self.asmOpOnly(.dbg_epilogue_begin);
1645 try self.asmPseudo(.pseudo_dbg_epilogue_begin_none);
14131646 }
14141647
14151648 // Drop them off at the rbrace.
14161649 _ = try self.addInst(.{
1417 .tag = .dbg_line,
1418 .ops = undefined,
1650 .tag = .pseudo,
1651 .ops = .pseudo_dbg_line_line_column,
14191652 .data = .{ .line_column = .{
14201653 .line = self.end_di_line,
14211654 .column = self.end_di_column,
......@@ -1480,12 +1713,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
14801713 .log,
14811714 .log2,
14821715 .log10,
1483 .floor,
1484 .ceil,
14851716 .round,
1486 .trunc_float,
14871717 => try self.airUnaryMath(inst),
14881718
1719 .floor => try self.airRound(inst, 0b1_0_01),
1720 .ceil => try self.airRound(inst, 0b1_0_10),
1721 .trunc_float => try self.airRound(inst, 0b1_0_11),
14891722 .sqrt => try self.airSqrt(inst),
14901723 .neg, .fabs => try self.airFloatSign(inst),
14911724
......@@ -1731,7 +1964,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
17311964 };
17321965 const tag_val = Value.initPayload(&tag_pl.base);
17331966 const tag_mcv = try self.genTypedValue(.{ .ty = enum_ty, .val = tag_val });
1734 try self.genBinOpMir(.cmp, enum_ty, enum_mcv, tag_mcv);
1967 try self.genBinOpMir(.{ ._, .cmp }, enum_ty, enum_mcv, tag_mcv);
17351968 const skip_reloc = try self.asmJccReloc(undefined, .ne);
17361969
17371970 try self.genSetMem(
......@@ -1751,7 +1984,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
17511984 try self.airTrap();
17521985
17531986 for (exitlude_jump_relocs) |reloc| try self.performReloc(reloc);
1754 try self.asmOpOnly(.ret);
1987 try self.asmOpOnly(.{ ._, .ret });
17551988 },
17561989 else => return self.fail(
17571990 "TODO implement {s} for {}",
......@@ -1919,6 +2152,11 @@ fn computeFrameLayout(self: *Self) !FrameLayout {
19192152 };
19202153}
19212154
2155fn getFrameAddrAlignment(self: *Self, frame_addr: FrameAddr) u32 {
2156 const alloc_align = @as(u32, 1) << self.frame_allocs.get(@enumToInt(frame_addr.index)).abi_align;
2157 return @min(alloc_align, @bitCast(u32, frame_addr.off) & (alloc_align - 1));
2158}
2159
19222160fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex {
19232161 const frame_allocs_slice = self.frame_allocs.slice();
19242162 const frame_size = frame_allocs_slice.items(.abi_size);
......@@ -1962,24 +2200,36 @@ fn allocTempRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool) !MCValue {
19622200 return self.allocRegOrMemAdvanced(elem_ty, null, reg_ok);
19632201}
19642202
1965fn allocRegOrMemAdvanced(self: *Self, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue {
1966 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse {
2203fn allocRegOrMemAdvanced(self: *Self, ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue {
2204 const abi_size = math.cast(u32, ty.abiSize(self.target.*)) orelse {
19672205 const mod = self.bin_file.options.module.?;
1968 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)});
2206 return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(mod)});
19692207 };
19702208
1971 if (reg_ok) {
1972 // Make sure the type can fit in a register before we try to allocate one.
1973 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
1974 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
1975 if (abi_size <= ptr_bytes) {
1976 if (self.register_manager.tryAllocReg(inst, regClassForType(elem_ty))) |reg| {
2209 if (reg_ok) need_mem: {
2210 if (abi_size <= @as(u32, switch (ty.zigTypeTag()) {
2211 .Float => switch (ty.floatBits(self.target.*)) {
2212 16, 32, 64, 128 => 16,
2213 80 => break :need_mem,
2214 else => unreachable,
2215 },
2216 .Vector => switch (ty.childType().zigTypeTag()) {
2217 .Float => switch (ty.childType().floatBits(self.target.*)) {
2218 16, 32, 64 => if (self.hasFeature(.avx)) 32 else 16,
2219 80, 128 => break :need_mem,
2220 else => unreachable,
2221 },
2222 else => break :need_mem,
2223 },
2224 else => 8,
2225 })) {
2226 if (self.register_manager.tryAllocReg(inst, regClassForType(ty))) |reg| {
19772227 return MCValue{ .register = registerAlias(reg, abi_size) };
19782228 }
19792229 }
19802230 }
19812231
1982 const frame_index = try self.allocFrameIndex(FrameAlloc.initType(elem_ty, self.target.*));
2232 const frame_index = try self.allocFrameIndex(FrameAlloc.initType(ty, self.target.*));
19832233 return .{ .load_frame = .{ .index = frame_index } };
19842234}
19852235
......@@ -2172,44 +2422,127 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void {
21722422fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {
21732423 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
21742424 const dst_ty = self.air.typeOfIndex(inst);
2425 const dst_bits = dst_ty.floatBits(self.target.*);
21752426 const src_ty = self.air.typeOf(ty_op.operand);
2176 if (dst_ty.floatBits(self.target.*) != 32 or src_ty.floatBits(self.target.*) != 64 or
2177 !Target.x86.featureSetHas(self.target.cpu.features, .sse2))
2178 return self.fail("TODO implement airFptrunc from {} to {}", .{
2179 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
2180 });
2427 const src_bits = src_ty.floatBits(self.target.*);
21812428
21822429 const src_mcv = try self.resolveInst(ty_op.operand);
21832430 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
21842431 src_mcv
21852432 else
21862433 try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);
2187 const dst_lock = self.register_manager.lockReg(dst_mcv.register);
2434 const dst_reg = dst_mcv.getReg().?.to128();
2435 const dst_lock = self.register_manager.lockReg(dst_reg);
21882436 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
21892437
2190 try self.genBinOpMir(.cvtsd2ss, src_ty, dst_mcv, src_mcv);
2438 if (dst_bits == 16 and self.hasFeature(.f16c)) {
2439 switch (src_bits) {
2440 32 => {
2441 const mat_src_reg = if (src_mcv.isRegister())
2442 src_mcv.getReg().?
2443 else
2444 try self.copyToTmpRegister(src_ty, src_mcv);
2445 try self.asmRegisterRegisterImmediate(
2446 .{ .v_, .cvtps2ph },
2447 dst_reg,
2448 mat_src_reg.to128(),
2449 Immediate.u(0b1_00),
2450 );
2451 },
2452 else => return self.fail("TODO implement airFptrunc from {} to {}", .{
2453 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
2454 }),
2455 }
2456 } else if (src_bits == 64 and dst_bits == 32) {
2457 if (self.hasFeature(.avx)) if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
2458 .{ .v_, .cvtsd2ss },
2459 dst_reg,
2460 dst_reg,
2461 src_mcv.mem(.qword),
2462 ) else try self.asmRegisterRegisterRegister(
2463 .{ .v_, .cvtsd2ss },
2464 dst_reg,
2465 dst_reg,
2466 (if (src_mcv.isRegister())
2467 src_mcv.getReg().?
2468 else
2469 try self.copyToTmpRegister(src_ty, src_mcv)).to128(),
2470 ) else if (src_mcv.isMemory()) try self.asmRegisterMemory(
2471 .{ ._, .cvtsd2ss },
2472 dst_reg,
2473 src_mcv.mem(.qword),
2474 ) else try self.asmRegisterRegister(
2475 .{ ._, .cvtsd2ss },
2476 dst_reg,
2477 (if (src_mcv.isRegister())
2478 src_mcv.getReg().?
2479 else
2480 try self.copyToTmpRegister(src_ty, src_mcv)).to128(),
2481 );
2482 } else return self.fail("TODO implement airFptrunc from {} to {}", .{
2483 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
2484 });
21912485 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
21922486}
21932487
21942488fn airFpext(self: *Self, inst: Air.Inst.Index) !void {
21952489 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
21962490 const dst_ty = self.air.typeOfIndex(inst);
2491 const dst_bits = dst_ty.floatBits(self.target.*);
21972492 const src_ty = self.air.typeOf(ty_op.operand);
2198 if (dst_ty.floatBits(self.target.*) != 64 or src_ty.floatBits(self.target.*) != 32 or
2199 !Target.x86.featureSetHas(self.target.cpu.features, .sse2))
2200 return self.fail("TODO implement airFpext from {} to {}", .{
2201 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
2202 });
2493 const src_bits = src_ty.floatBits(self.target.*);
22032494
22042495 const src_mcv = try self.resolveInst(ty_op.operand);
22052496 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
22062497 src_mcv
22072498 else
22082499 try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);
2209 const dst_lock = self.register_manager.lockReg(dst_mcv.register);
2500 const dst_reg = dst_mcv.getReg().?.to128();
2501 const dst_lock = self.register_manager.lockReg(dst_reg);
22102502 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
22112503
2212 try self.genBinOpMir(.cvtss2sd, src_ty, dst_mcv, src_mcv);
2504 if (src_bits == 16 and self.hasFeature(.f16c)) {
2505 const mat_src_reg = if (src_mcv.isRegister())
2506 src_mcv.getReg().?
2507 else
2508 try self.copyToTmpRegister(src_ty, src_mcv);
2509 try self.asmRegisterRegister(.{ .v_, .cvtph2ps }, dst_reg, mat_src_reg.to128());
2510 switch (dst_bits) {
2511 32 => {},
2512 64 => try self.asmRegisterRegisterRegister(.{ .v_, .cvtss2sd }, dst_reg, dst_reg, dst_reg),
2513 else => return self.fail("TODO implement airFpext from {} to {}", .{
2514 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
2515 }),
2516 }
2517 } else if (src_bits == 32 and dst_bits == 64) {
2518 if (self.hasFeature(.avx)) if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
2519 .{ .v_, .cvtss2sd },
2520 dst_reg,
2521 dst_reg,
2522 src_mcv.mem(.dword),
2523 ) else try self.asmRegisterRegisterRegister(
2524 .{ .v_, .cvtss2sd },
2525 dst_reg,
2526 dst_reg,
2527 (if (src_mcv.isRegister())
2528 src_mcv.getReg().?
2529 else
2530 try self.copyToTmpRegister(src_ty, src_mcv)).to128(),
2531 ) else if (src_mcv.isMemory()) try self.asmRegisterMemory(
2532 .{ ._, .cvtss2sd },
2533 dst_reg,
2534 src_mcv.mem(.dword),
2535 ) else try self.asmRegisterRegister(
2536 .{ ._, .cvtss2sd },
2537 dst_reg,
2538 (if (src_mcv.isRegister())
2539 src_mcv.getReg().?
2540 else
2541 try self.copyToTmpRegister(src_ty, src_mcv)).to128(),
2542 );
2543 } else return self.fail("TODO implement airFpext from {} to {}", .{
2544 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
2545 });
22132546 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
22142547}
22152548
......@@ -2241,11 +2574,11 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
22412574 switch (dst_mcv) {
22422575 .register => |dst_reg| {
22432576 const min_abi_size = @min(dst_abi_size, src_abi_size);
2244 const tag: Mir.Inst.Tag = switch (signedness) {
2245 .signed => .movsx,
2246 .unsigned => if (min_abi_size > 2) .mov else .movzx,
2577 const tag: Mir.Inst.FixedTag = switch (signedness) {
2578 .signed => if (min_abi_size >= 4) .{ ._d, .movsx } else .{ ._, .movsx },
2579 .unsigned => if (min_abi_size >= 4) .{ ._, .mov } else .{ ._, .movzx },
22472580 };
2248 const dst_alias = switch (tag) {
2581 const dst_alias = switch (tag[1]) {
22492582 .movsx => dst_reg.to64(),
22502583 .mov, .movzx => if (min_abi_size > 4) dst_reg.to64() else dst_reg.to32(),
22512584 else => unreachable,
......@@ -2274,14 +2607,24 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
22742607 try self.genCopy(min_ty, dst_mcv, src_mcv);
22752608 const extra = dst_abi_size * 8 - dst_int_info.bits;
22762609 if (extra > 0) {
2277 try self.genShiftBinOpMir(switch (signedness) {
2278 .signed => .sal,
2279 .unsigned => .shl,
2280 }, dst_ty, dst_mcv, .{ .immediate = extra });
2281 try self.genShiftBinOpMir(switch (signedness) {
2282 .signed => .sar,
2283 .unsigned => .shr,
2284 }, dst_ty, dst_mcv, .{ .immediate = extra });
2610 try self.genShiftBinOpMir(
2611 switch (signedness) {
2612 .signed => .{ ._l, .sa },
2613 .unsigned => .{ ._l, .sh },
2614 },
2615 dst_ty,
2616 dst_mcv,
2617 .{ .immediate = extra },
2618 );
2619 try self.genShiftBinOpMir(
2620 switch (signedness) {
2621 .signed => .{ ._r, .sa },
2622 .unsigned => .{ ._r, .sh },
2623 },
2624 dst_ty,
2625 dst_mcv,
2626 .{ .immediate = extra },
2627 );
22852628 }
22862629 },
22872630 }
......@@ -2466,8 +2809,8 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
24662809 const reg_bits = self.regBitSize(ty);
24672810 const cc: Condition = if (ty.isSignedInt()) cc: {
24682811 try self.genSetReg(limit_reg, ty, dst_mcv);
2469 try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
2470 try self.genBinOpMir(.xor, ty, limit_mcv, .{
2812 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
2813 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
24712814 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
24722815 });
24732816 break :cc .o;
......@@ -2477,7 +2820,7 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
24772820 });
24782821 break :cc .c;
24792822 };
2480 try self.genBinOpMir(.add, ty, dst_mcv, rhs_mcv);
2823 try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, rhs_mcv);
24812824
24822825 const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2);
24832826 try self.asmCmovccRegisterRegister(
......@@ -2517,8 +2860,8 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
25172860 const reg_bits = self.regBitSize(ty);
25182861 const cc: Condition = if (ty.isSignedInt()) cc: {
25192862 try self.genSetReg(limit_reg, ty, dst_mcv);
2520 try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
2521 try self.genBinOpMir(.xor, ty, limit_mcv, .{
2863 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
2864 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
25222865 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
25232866 });
25242867 break :cc .o;
......@@ -2526,7 +2869,7 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
25262869 try self.genSetReg(limit_reg, ty, .{ .immediate = 0 });
25272870 break :cc .c;
25282871 };
2529 try self.genBinOpMir(.sub, ty, dst_mcv, rhs_mcv);
2872 try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, rhs_mcv);
25302873
25312874 const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2);
25322875 try self.asmCmovccRegisterRegister(
......@@ -2568,9 +2911,9 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
25682911 const reg_bits = self.regBitSize(ty);
25692912 const cc: Condition = if (ty.isSignedInt()) cc: {
25702913 try self.genSetReg(limit_reg, ty, lhs_mcv);
2571 try self.genBinOpMir(.xor, ty, limit_mcv, rhs_mcv);
2572 try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
2573 try self.genBinOpMir(.xor, ty, limit_mcv, .{
2914 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, rhs_mcv);
2915 try self.genShiftBinOpMir(.{ ._, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
2916 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
25742917 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
25752918 });
25762919 break :cc .o;
......@@ -2683,7 +3026,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
26833026 };
26843027 defer if (tmp_lock) |lock| self.register_manager.unlockReg(lock);
26853028
2686 try self.genBinOpMir(.cmp, lhs_ty, tmp_mcv, lhs);
3029 try self.genBinOpMir(.{ ._, .cmp }, lhs_ty, tmp_mcv, lhs);
26873030 const cc = Condition.ne;
26883031
26893032 const tuple_ty = self.air.typeOfIndex(inst);
......@@ -2770,12 +3113,17 @@ fn genSetFrameTruncatedOverflowCompare(
27703113 src_mcv;
27713114 try self.genSetReg(scratch_reg, hi_limb_ty, hi_limb_mcv);
27723115 try self.truncateRegister(hi_limb_ty, scratch_reg);
2773 try self.genBinOpMir(.cmp, hi_limb_ty, .{ .register = scratch_reg }, hi_limb_mcv);
3116 try self.genBinOpMir(.{ ._, .cmp }, hi_limb_ty, .{ .register = scratch_reg }, hi_limb_mcv);
27743117
27753118 const eq_reg = temp_regs[2];
27763119 if (overflow_cc) |_| {
27773120 try self.asmSetccRegister(eq_reg.to8(), .ne);
2778 try self.genBinOpMir(.@"or", Type.u8, .{ .register = overflow_reg }, .{ .register = eq_reg });
3121 try self.genBinOpMir(
3122 .{ ._, .@"or" },
3123 Type.u8,
3124 .{ .register = overflow_reg },
3125 .{ .register = eq_reg },
3126 );
27793127 }
27803128
27813129 const payload_off = @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*));
......@@ -2904,28 +3252,25 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
29043252/// Generates signed or unsigned integer multiplication/division.
29053253/// Clobbers .rax and .rdx registers.
29063254/// Quotient is saved in .rax and remainder in .rdx.
2907fn genIntMulDivOpMir(
2908 self: *Self,
2909 tag: Mir.Inst.Tag,
2910 ty: Type,
2911 lhs: MCValue,
2912 rhs: MCValue,
2913) !void {
3255fn genIntMulDivOpMir(self: *Self, tag: Mir.Inst.FixedTag, ty: Type, lhs: MCValue, rhs: MCValue) !void {
29143256 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
29153257 if (abi_size > 8) {
29163258 return self.fail("TODO implement genIntMulDivOpMir for ABI size larger than 8", .{});
29173259 }
29183260
29193261 try self.genSetReg(.rax, ty, lhs);
2920 switch (tag) {
3262 switch (tag[1]) {
29213263 else => unreachable,
2922 .mul, .imul => {},
2923 .div => try self.asmRegisterRegister(.xor, .edx, .edx),
2924 .idiv => switch (self.regBitSize(ty)) {
2925 8 => try self.asmOpOnly(.cbw),
2926 16 => try self.asmOpOnly(.cwd),
2927 32 => try self.asmOpOnly(.cdq),
2928 64 => try self.asmOpOnly(.cqo),
3264 .mul => {},
3265 .div => switch (tag[0]) {
3266 ._ => try self.asmRegisterRegister(.{ ._, .xor }, .edx, .edx),
3267 .i_ => switch (self.regBitSize(ty)) {
3268 8 => try self.asmOpOnly(.{ ._, .cbw }),
3269 16 => try self.asmOpOnly(.{ ._, .cwd }),
3270 32 => try self.asmOpOnly(.{ ._, .cdq }),
3271 64 => try self.asmOpOnly(.{ ._, .cqo }),
3272 else => unreachable,
3273 },
29293274 else => unreachable,
29303275 },
29313276 }
......@@ -2963,23 +3308,28 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
29633308 const divisor_lock = self.register_manager.lockReg(divisor);
29643309 defer if (divisor_lock) |lock| self.register_manager.unlockReg(lock);
29653310
2966 try self.genIntMulDivOpMir(switch (int_info.signedness) {
2967 .signed => .idiv,
2968 .unsigned => .div,
2969 }, ty, .{ .register = dividend }, .{ .register = divisor });
3311 try self.genIntMulDivOpMir(
3312 switch (int_info.signedness) {
3313 .signed => .{ .i_, .div },
3314 .unsigned => .{ ._, .div },
3315 },
3316 ty,
3317 .{ .register = dividend },
3318 .{ .register = divisor },
3319 );
29703320
29713321 try self.asmRegisterRegister(
2972 .xor,
3322 .{ ._, .xor },
29733323 registerAlias(divisor, abi_size),
29743324 registerAlias(dividend, abi_size),
29753325 );
29763326 try self.asmRegisterImmediate(
2977 .sar,
3327 .{ ._r, .sa },
29783328 registerAlias(divisor, abi_size),
29793329 Immediate.u(int_info.bits - 1),
29803330 );
29813331 try self.asmRegisterRegister(
2982 .@"test",
3332 .{ ._, .@"test" },
29833333 registerAlias(.rdx, abi_size),
29843334 registerAlias(.rdx, abi_size),
29853335 );
......@@ -2988,7 +3338,7 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
29883338 registerAlias(.rdx, abi_size),
29893339 .z,
29903340 );
2991 try self.genBinOpMir(.add, ty, .{ .register = divisor }, .{ .register = .rax });
3341 try self.genBinOpMir(.{ ._, .add }, ty, .{ .register = divisor }, .{ .register = .rax });
29923342 return MCValue{ .register = divisor };
29933343}
29943344
......@@ -3110,7 +3460,12 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
31103460 const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);
31113461 if (err_off > 0) {
31123462 const shift = @intCast(u6, err_off * 8);
3113 try self.genShiftBinOpMir(.shr, err_union_ty, result, .{ .immediate = shift });
3463 try self.genShiftBinOpMir(
3464 .{ ._r, .sh },
3465 err_union_ty,
3466 result,
3467 .{ .immediate = shift },
3468 );
31143469 } else {
31153470 try self.truncateRegister(Type.anyerror, result.register);
31163471 }
......@@ -3162,7 +3517,12 @@ fn genUnwrapErrorUnionPayloadMir(
31623517 .{ .register = try self.copyToTmpRegister(err_union_ty, err_union) };
31633518 if (payload_off > 0) {
31643519 const shift = @intCast(u6, payload_off * 8);
3165 try self.genShiftBinOpMir(.shr, err_union_ty, result_mcv, .{ .immediate = shift });
3520 try self.genShiftBinOpMir(
3521 .{ ._r, .sh },
3522 err_union_ty,
3523 result_mcv,
3524 .{ .immediate = shift },
3525 );
31663526 } else {
31673527 try self.truncateRegister(payload_ty, result_mcv.register);
31683528 }
......@@ -3199,7 +3559,7 @@ fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void {
31993559 const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*));
32003560 const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*));
32013561 try self.asmRegisterMemory(
3202 .mov,
3562 .{ ._, .mov },
32033563 registerAlias(dst_reg, err_abi_size),
32043564 Memory.sib(Memory.PtrSize.fromSize(err_abi_size), .{
32053565 .base = .{ .reg = src_reg },
......@@ -3237,7 +3597,7 @@ fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
32373597 const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, self.target.*));
32383598 const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
32393599 try self.asmRegisterMemory(
3240 .lea,
3600 .{ ._, .lea },
32413601 registerAlias(dst_reg, dst_abi_size),
32423602 Memory.sib(.qword, .{ .base = .{ .reg = src_reg }, .disp = pl_off }),
32433603 );
......@@ -3263,7 +3623,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
32633623 const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*));
32643624 const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*));
32653625 try self.asmMemoryImmediate(
3266 .mov,
3626 .{ ._, .mov },
32673627 Memory.sib(Memory.PtrSize.fromSize(err_abi_size), .{
32683628 .base = .{ .reg = src_reg },
32693629 .disp = err_off,
......@@ -3284,7 +3644,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
32843644 const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, self.target.*));
32853645 const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
32863646 try self.asmRegisterMemory(
3287 .lea,
3647 .{ ._, .lea },
32883648 registerAlias(dst_reg, dst_abi_size),
32893649 Memory.sib(.qword, .{ .base = .{ .reg = src_reg }, .disp = pl_off }),
32903650 );
......@@ -3335,13 +3695,13 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
33353695 else => unreachable,
33363696
33373697 .register => |opt_reg| try self.asmRegisterImmediate(
3338 .bts,
3698 .{ ._s, .bt },
33393699 opt_reg,
33403700 Immediate.u(@intCast(u6, pl_abi_size * 8)),
33413701 ),
33423702
33433703 .load_frame => |frame_addr| try self.asmMemoryImmediate(
3344 .mov,
3704 .{ ._, .mov },
33453705 Memory.sib(.byte, .{
33463706 .base = .{ .frame = frame_addr.index },
33473707 .disp = frame_addr.off + pl_abi_size,
......@@ -3453,7 +3813,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {
34533813
34543814 const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
34553815 try self.asmRegisterMemory(
3456 .lea,
3816 .{ ._, .lea },
34573817 registerAlias(dst_reg, dst_abi_size),
34583818 Memory.sib(.qword, .{
34593819 .base = .{ .reg = src_reg },
......@@ -3527,7 +3887,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
35273887 try self.genSetReg(addr_reg, Type.usize, slice_mcv);
35283888 // TODO we could allocate register here, but need to expect addr register and potentially
35293889 // offset register.
3530 try self.genBinOpMir(.add, slice_ptr_field_type, .{ .register = addr_reg }, .{
3890 try self.genBinOpMir(.{ ._, .add }, slice_ptr_field_type, .{ .register = addr_reg }, .{
35313891 .register = offset_reg,
35323892 });
35333893 return MCValue{ .register = addr_reg.to64() };
......@@ -3585,13 +3945,13 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
35853945 const frame_index = try self.allocFrameIndex(FrameAlloc.initType(array_ty, self.target.*));
35863946 try self.genSetMem(.{ .frame = frame_index }, 0, array_ty, array);
35873947 try self.asmRegisterMemory(
3588 .lea,
3948 .{ ._, .lea },
35893949 addr_reg,
35903950 Memory.sib(.qword, .{ .base = .{ .frame = frame_index } }),
35913951 );
35923952 },
35933953 .load_frame => |frame_addr| try self.asmRegisterMemory(
3594 .lea,
3954 .{ ._, .lea },
35953955 addr_reg,
35963956 Memory.sib(.qword, .{ .base = .{ .frame = frame_addr.index }, .disp = frame_addr.off }),
35973957 ),
......@@ -3607,7 +3967,12 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
36073967 // TODO we could allocate register here, but need to expect addr register and potentially
36083968 // offset register.
36093969 const dst_mcv = try self.allocRegOrMem(inst, false);
3610 try self.genBinOpMir(.add, Type.usize, .{ .register = addr_reg }, .{ .register = offset_reg });
3970 try self.genBinOpMir(
3971 .{ ._, .add },
3972 Type.usize,
3973 .{ .register = addr_reg },
3974 .{ .register = offset_reg },
3975 );
36113976 try self.genCopy(elem_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });
36123977
36133978 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
......@@ -3641,7 +4006,11 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
36414006 try self.copyToTmpRegister(ptr_ty, ptr_mcv);
36424007 const elem_ptr_lock = self.register_manager.lockRegAssumeUnused(elem_ptr_reg);
36434008 defer self.register_manager.unlockReg(elem_ptr_lock);
3644 try self.asmRegisterRegister(.add, elem_ptr_reg, offset_reg);
4009 try self.asmRegisterRegister(
4010 .{ ._, .add },
4011 elem_ptr_reg,
4012 offset_reg,
4013 );
36454014
36464015 const dst_mcv = try self.allocRegOrMem(inst, true);
36474016 const dst_lock = switch (dst_mcv) {
......@@ -3681,7 +4050,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
36814050 defer self.register_manager.unlockReg(offset_reg_lock);
36824051
36834052 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr);
3684 try self.genBinOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
4053 try self.genBinOpMir(.{ ._, .add }, ptr_ty, dst_mcv, .{ .register = offset_reg });
36854054
36864055 return self.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none });
36874056}
......@@ -3714,7 +4083,12 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
37144083 const adjusted_ptr: MCValue = if (layout.payload_size > 0 and layout.tag_align < layout.payload_align) blk: {
37154084 // TODO reusing the operand
37164085 const reg = try self.copyToTmpRegister(ptr_union_ty, ptr);
3717 try self.genBinOpMir(.add, ptr_union_ty, .{ .register = reg }, .{ .immediate = layout.payload_size });
4086 try self.genBinOpMir(
4087 .{ ._, .add },
4088 ptr_union_ty,
4089 .{ .register = reg },
4090 .{ .immediate = layout.payload_size },
4091 );
37184092 break :blk MCValue{ .register = reg };
37194093 } else ptr;
37204094
......@@ -3767,7 +4141,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
37674141 else
37684142 0;
37694143 const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand);
3770 try self.genShiftBinOpMir(.shr, Type.usize, result, .{ .immediate = shift });
4144 try self.genShiftBinOpMir(.{ ._r, .sh }, Type.usize, result, .{ .immediate = shift });
37714145 break :blk MCValue{
37724146 .register = registerAlias(result.register, @intCast(u32, layout.tag_size)),
37734147 };
......@@ -3798,24 +4172,53 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
37984172
37994173 const dst_reg = try self.register_manager.allocReg(inst, gp);
38004174 const dst_mcv = MCValue{ .register = dst_reg };
3801 const dst_lock = self.register_manager.lockReg(dst_reg);
3802 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
4175 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
4176 defer self.register_manager.unlockReg(dst_lock);
38034177
3804 if (Target.x86.featureSetHas(self.target.cpu.features, .lzcnt)) {
3805 try self.genBinOpMir(.lzcnt, src_ty, dst_mcv, mat_src_mcv);
3806 const extra_bits = self.regExtraBits(src_ty);
3807 if (extra_bits > 0) {
3808 try self.genBinOpMir(.sub, dst_ty, dst_mcv, .{ .immediate = extra_bits });
3809 }
4178 const src_bits = src_ty.bitSize(self.target.*);
4179 if (self.hasFeature(.lzcnt)) {
4180 if (src_bits <= 64) {
4181 try self.genBinOpMir(.{ ._, .lzcnt }, src_ty, dst_mcv, mat_src_mcv);
4182
4183 const extra_bits = self.regExtraBits(src_ty);
4184 if (extra_bits > 0) {
4185 try self.genBinOpMir(.{ ._, .sub }, dst_ty, dst_mcv, .{ .immediate = extra_bits });
4186 }
4187 } else if (src_bits <= 128) {
4188 const tmp_reg = try self.register_manager.allocReg(null, gp);
4189 const tmp_mcv = MCValue{ .register = tmp_reg };
4190 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
4191 defer self.register_manager.unlockReg(tmp_lock);
4192
4193 try self.genBinOpMir(.{ ._, .lzcnt }, Type.u64, dst_mcv, mat_src_mcv);
4194 try self.genBinOpMir(.{ ._, .add }, dst_ty, dst_mcv, .{ .immediate = 64 });
4195 try self.genBinOpMir(
4196 .{ ._, .lzcnt },
4197 Type.u64,
4198 tmp_mcv,
4199 mat_src_mcv.address().offset(8).deref(),
4200 );
4201 try self.asmCmovccRegisterRegister(dst_reg.to32(), tmp_reg.to32(), .nc);
4202
4203 if (src_bits < 128) {
4204 try self.genBinOpMir(
4205 .{ ._, .sub },
4206 dst_ty,
4207 dst_mcv,
4208 .{ .immediate = 128 - src_bits },
4209 );
4210 }
4211 } else return self.fail("TODO airClz of {}", .{src_ty.fmt(self.bin_file.options.module.?)});
38104212 break :result dst_mcv;
38114213 }
38124214
3813 const src_bits = src_ty.bitSize(self.target.*);
4215 if (src_bits > 64)
4216 return self.fail("TODO airClz of {}", .{src_ty.fmt(self.bin_file.options.module.?)});
38144217 if (math.isPowerOfTwo(src_bits)) {
38154218 const imm_reg = try self.copyToTmpRegister(dst_ty, .{
38164219 .immediate = src_bits ^ (src_bits - 1),
38174220 });
3818 try self.genBinOpMir(.bsr, src_ty, dst_mcv, mat_src_mcv);
4221 try self.genBinOpMir(.{ ._, .bsr }, src_ty, dst_mcv, mat_src_mcv);
38194222
38204223 const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);
38214224 try self.asmCmovccRegisterRegister(
......@@ -3824,12 +4227,12 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
38244227 .z,
38254228 );
38264229
3827 try self.genBinOpMir(.xor, dst_ty, dst_mcv, .{ .immediate = src_bits - 1 });
4230 try self.genBinOpMir(.{ ._, .xor }, dst_ty, dst_mcv, .{ .immediate = src_bits - 1 });
38284231 } else {
38294232 const imm_reg = try self.copyToTmpRegister(dst_ty, .{
38304233 .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - self.regBitSize(dst_ty)),
38314234 });
3832 try self.genBinOpMir(.bsr, src_ty, dst_mcv, mat_src_mcv);
4235 try self.genBinOpMir(.{ ._, .bsr }, src_ty, dst_mcv, mat_src_mcv);
38334236
38344237 const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);
38354238 try self.asmCmovccRegisterRegister(
......@@ -3839,7 +4242,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
38394242 );
38404243
38414244 try self.genSetReg(dst_reg, dst_ty, .{ .immediate = src_bits - 1 });
3842 try self.genBinOpMir(.sub, dst_ty, dst_mcv, .{ .register = imm_reg });
4245 try self.genBinOpMir(.{ ._, .sub }, dst_ty, dst_mcv, .{ .register = imm_reg });
38434246 }
38444247 break :result dst_mcv;
38454248 };
......@@ -3869,27 +4272,55 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
38694272 const dst_lock = self.register_manager.lockReg(dst_reg);
38704273 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
38714274
3872 if (Target.x86.featureSetHas(self.target.cpu.features, .bmi)) {
3873 const extra_bits = self.regExtraBits(src_ty);
3874 const masked_mcv = if (extra_bits > 0) masked: {
3875 const mask_mcv = MCValue{
3876 .immediate = ((@as(u64, 1) << @intCast(u6, extra_bits)) - 1) <<
3877 @intCast(u6, src_bits),
3878 };
3879 const tmp_mcv = tmp: {
3880 if (src_mcv.isImmediate() or self.liveness.operandDies(inst, 0)) break :tmp src_mcv;
3881 try self.genSetReg(dst_reg, src_ty, src_mcv);
3882 break :tmp dst_mcv;
3883 };
3884 try self.genBinOpMir(.@"or", src_ty, tmp_mcv, mask_mcv);
3885 break :masked tmp_mcv;
3886 } else mat_src_mcv;
3887 try self.genBinOpMir(.tzcnt, src_ty, dst_mcv, masked_mcv);
4275 if (self.hasFeature(.bmi)) {
4276 if (src_bits <= 64) {
4277 const extra_bits = self.regExtraBits(src_ty);
4278 const masked_mcv = if (extra_bits > 0) masked: {
4279 const tmp_mcv = tmp: {
4280 if (src_mcv.isImmediate() or self.liveness.operandDies(inst, 0))
4281 break :tmp src_mcv;
4282 try self.genSetReg(dst_reg, src_ty, src_mcv);
4283 break :tmp dst_mcv;
4284 };
4285 try self.genBinOpMir(
4286 .{ ._, .@"or" },
4287 src_ty,
4288 tmp_mcv,
4289 .{ .immediate = (@as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - extra_bits)) <<
4290 @intCast(u6, src_bits) },
4291 );
4292 break :masked tmp_mcv;
4293 } else mat_src_mcv;
4294 try self.genBinOpMir(.{ ._, .tzcnt }, src_ty, dst_mcv, masked_mcv);
4295 } else if (src_bits <= 128) {
4296 const tmp_reg = try self.register_manager.allocReg(null, gp);
4297 const tmp_mcv = MCValue{ .register = tmp_reg };
4298 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
4299 defer self.register_manager.unlockReg(tmp_lock);
4300
4301 const masked_mcv = if (src_bits < 128) masked: {
4302 try self.genCopy(Type.u64, dst_mcv, mat_src_mcv.address().offset(8).deref());
4303 try self.genBinOpMir(
4304 .{ ._, .@"or" },
4305 Type.u64,
4306 dst_mcv,
4307 .{ .immediate = @as(u64, math.maxInt(u64)) << @intCast(u6, src_bits - 64) },
4308 );
4309 break :masked dst_mcv;
4310 } else mat_src_mcv.address().offset(8).deref();
4311 try self.genBinOpMir(.{ ._, .tzcnt }, Type.u64, dst_mcv, masked_mcv);
4312 try self.genBinOpMir(.{ ._, .add }, dst_ty, dst_mcv, .{ .immediate = 64 });
4313 try self.genBinOpMir(.{ ._, .tzcnt }, Type.u64, tmp_mcv, mat_src_mcv);
4314 try self.asmCmovccRegisterRegister(dst_reg.to32(), tmp_reg.to32(), .nc);
4315 } else return self.fail("TODO airCtz of {}", .{src_ty.fmt(self.bin_file.options.module.?)});
38884316 break :result dst_mcv;
38894317 }
38904318
4319 if (src_bits > 64)
4320 return self.fail("TODO airCtz of {}", .{src_ty.fmt(self.bin_file.options.module.?)});
4321
38914322 const width_reg = try self.copyToTmpRegister(dst_ty, .{ .immediate = src_bits });
3892 try self.genBinOpMir(.bsf, src_ty, dst_mcv, mat_src_mcv);
4323 try self.genBinOpMir(.{ ._, .bsf }, src_ty, dst_mcv, mat_src_mcv);
38934324
38944325 const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);
38954326 try self.asmCmovccRegisterRegister(
......@@ -3909,7 +4340,7 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
39094340 const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));
39104341 const src_mcv = try self.resolveInst(ty_op.operand);
39114342
3912 if (Target.x86.featureSetHas(self.target.cpu.features, .popcnt)) {
4343 if (self.hasFeature(.popcnt)) {
39134344 const mat_src_mcv = switch (src_mcv) {
39144345 .immediate => MCValue{ .register = try self.copyToTmpRegister(src_ty, src_mcv) },
39154346 else => src_mcv,
......@@ -3927,7 +4358,7 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
39274358 .{ .register = try self.register_manager.allocReg(inst, gp) };
39284359
39294360 const popcnt_ty = if (src_abi_size > 1) src_ty else Type.u16;
3930 try self.genBinOpMir(.popcnt, popcnt_ty, dst_mcv, mat_src_mcv);
4361 try self.genBinOpMir(.{ ._, .popcnt }, popcnt_ty, dst_mcv, mat_src_mcv);
39314362 break :result dst_mcv;
39324363 }
39334364
......@@ -3958,54 +4389,54 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
39584389 undefined;
39594390
39604391 // dst = operand
3961 try self.asmRegisterRegister(.mov, tmp, dst);
4392 try self.asmRegisterRegister(.{ ._, .mov }, tmp, dst);
39624393 // tmp = operand
3963 try self.asmRegisterImmediate(.shr, tmp, Immediate.u(1));
4394 try self.asmRegisterImmediate(.{ ._r, .sh }, tmp, Immediate.u(1));
39644395 // tmp = operand >> 1
39654396 if (src_abi_size > 4) {
3966 try self.asmRegisterImmediate(.mov, imm, imm_0_1);
3967 try self.asmRegisterRegister(.@"and", tmp, imm);
3968 } else try self.asmRegisterImmediate(.@"and", tmp, imm_0_1);
4397 try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_0_1);
4398 try self.asmRegisterRegister(.{ ._, .@"and" }, tmp, imm);
4399 } else try self.asmRegisterImmediate(.{ ._, .@"and" }, tmp, imm_0_1);
39694400 // tmp = (operand >> 1) & 0x55...55
3970 try self.asmRegisterRegister(.sub, dst, tmp);
4401 try self.asmRegisterRegister(.{ ._, .sub }, dst, tmp);
39714402 // dst = temp1 = operand - ((operand >> 1) & 0x55...55)
3972 try self.asmRegisterRegister(.mov, tmp, dst);
4403 try self.asmRegisterRegister(.{ ._, .mov }, tmp, dst);
39734404 // tmp = temp1
3974 try self.asmRegisterImmediate(.shr, dst, Immediate.u(2));
4405 try self.asmRegisterImmediate(.{ ._r, .sh }, dst, Immediate.u(2));
39754406 // dst = temp1 >> 2
39764407 if (src_abi_size > 4) {
3977 try self.asmRegisterImmediate(.mov, imm, imm_00_11);
3978 try self.asmRegisterRegister(.@"and", tmp, imm);
3979 try self.asmRegisterRegister(.@"and", dst, imm);
4408 try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_00_11);
4409 try self.asmRegisterRegister(.{ ._, .@"and" }, tmp, imm);
4410 try self.asmRegisterRegister(.{ ._, .@"and" }, dst, imm);
39804411 } else {
3981 try self.asmRegisterImmediate(.@"and", tmp, imm_00_11);
3982 try self.asmRegisterImmediate(.@"and", dst, imm_00_11);
4412 try self.asmRegisterImmediate(.{ ._, .@"and" }, tmp, imm_00_11);
4413 try self.asmRegisterImmediate(.{ ._, .@"and" }, dst, imm_00_11);
39834414 }
39844415 // tmp = temp1 & 0x33...33
39854416 // dst = (temp1 >> 2) & 0x33...33
3986 try self.asmRegisterRegister(.add, tmp, dst);
4417 try self.asmRegisterRegister(.{ ._, .add }, tmp, dst);
39874418 // tmp = temp2 = (temp1 & 0x33...33) + ((temp1 >> 2) & 0x33...33)
3988 try self.asmRegisterRegister(.mov, dst, tmp);
4419 try self.asmRegisterRegister(.{ ._, .mov }, dst, tmp);
39894420 // dst = temp2
3990 try self.asmRegisterImmediate(.shr, tmp, Immediate.u(4));
4421 try self.asmRegisterImmediate(.{ ._r, .sh }, tmp, Immediate.u(4));
39914422 // tmp = temp2 >> 4
3992 try self.asmRegisterRegister(.add, dst, tmp);
4423 try self.asmRegisterRegister(.{ ._, .add }, dst, tmp);
39934424 // dst = temp2 + (temp2 >> 4)
39944425 if (src_abi_size > 4) {
3995 try self.asmRegisterImmediate(.mov, imm, imm_0000_1111);
3996 try self.asmRegisterImmediate(.mov, tmp, imm_0000_0001);
3997 try self.asmRegisterRegister(.@"and", dst, imm);
3998 try self.asmRegisterRegister(.imul, dst, tmp);
4426 try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_0000_1111);
4427 try self.asmRegisterImmediate(.{ ._, .mov }, tmp, imm_0000_0001);
4428 try self.asmRegisterRegister(.{ ._, .@"and" }, dst, imm);
4429 try self.asmRegisterRegister(.{ .i_, .mul }, dst, tmp);
39994430 } else {
4000 try self.asmRegisterImmediate(.@"and", dst, imm_0000_1111);
4431 try self.asmRegisterImmediate(.{ ._, .@"and" }, dst, imm_0000_1111);
40014432 if (src_abi_size > 1) {
4002 try self.asmRegisterRegisterImmediate(.imul, dst, dst, imm_0000_0001);
4433 try self.asmRegisterRegisterImmediate(.{ .i_, .mul }, dst, dst, imm_0000_0001);
40034434 }
40044435 }
40054436 // dst = temp3 = (temp2 + (temp2 >> 4)) & 0x0f...0f
40064437 // dst = temp3 * 0x01...01
40074438 if (src_abi_size > 1) {
4008 try self.asmRegisterImmediate(.shr, dst, Immediate.u((src_abi_size - 1) * 8));
4439 try self.asmRegisterImmediate(.{ ._r, .sh }, dst, Immediate.u((src_abi_size - 1) * 8));
40094440 }
40104441 // dst = (temp3 * 0x01...01) >> (bits - 8)
40114442 }
......@@ -4034,11 +4465,11 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m
40344465 16 => if ((mem_ok or src_mcv.isRegister()) and
40354466 self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
40364467 {
4037 try self.genBinOpMir(.rol, src_ty, src_mcv, .{ .immediate = 8 });
4468 try self.genBinOpMir(.{ ._l, .ro }, src_ty, src_mcv, .{ .immediate = 8 });
40384469 return src_mcv;
40394470 },
40404471 32, 64 => if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) {
4041 try self.genUnOpMir(.bswap, src_ty, src_mcv);
4472 try self.genUnOpMir(.{ ._, .bswap }, src_ty, src_mcv);
40424473 return src_mcv;
40434474 },
40444475 }
......@@ -4055,10 +4486,10 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m
40554486 try self.genSetReg(dst_mcv.register, src_ty, src_mcv);
40564487 switch (src_bits) {
40574488 else => unreachable,
4058 16 => try self.genBinOpMir(.rol, src_ty, dst_mcv, .{ .immediate = 8 }),
4059 32, 64 => try self.genUnOpMir(.bswap, src_ty, dst_mcv),
4489 16 => try self.genBinOpMir(.{ ._l, .ro }, src_ty, dst_mcv, .{ .immediate = 8 }),
4490 32, 64 => try self.genUnOpMir(.{ ._, .bswap }, src_ty, dst_mcv),
40604491 }
4061 } else try self.genBinOpMir(.movbe, src_ty, dst_mcv, src_mcv);
4492 } else try self.genBinOpMir(.{ ._, .movbe }, src_ty, dst_mcv, src_mcv);
40624493 return dst_mcv;
40634494 }
40644495
......@@ -4067,7 +4498,7 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m
40674498 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
40684499 defer self.register_manager.unlockReg(dst_lock);
40694500
4070 try self.genBinOpMir(.movbe, src_ty, dst_mcv, src_mcv);
4501 try self.genBinOpMir(.{ ._, .movbe }, src_ty, dst_mcv, src_mcv);
40714502 return dst_mcv;
40724503}
40734504
......@@ -4081,7 +4512,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
40814512 switch (self.regExtraBits(src_ty)) {
40824513 0 => {},
40834514 else => |extra| try self.genBinOpMir(
4084 if (src_ty.isSignedInt()) .sar else .shr,
4515 if (src_ty.isSignedInt()) .{ ._r, .sa } else .{ ._r, .sh },
40854516 src_ty,
40864517 dst_mcv,
40874518 .{ .immediate = extra },
......@@ -4121,40 +4552,40 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
41214552 const imm_0_1 = Immediate.u(mask / 0b1_1);
41224553
41234554 // dst = temp1 = bswap(operand)
4124 try self.asmRegisterRegister(.mov, tmp, dst);
4555 try self.asmRegisterRegister(.{ ._, .mov }, tmp, dst);
41254556 // tmp = temp1
4126 try self.asmRegisterImmediate(.shr, dst, Immediate.u(4));
4557 try self.asmRegisterImmediate(.{ ._r, .sh }, dst, Immediate.u(4));
41274558 // dst = temp1 >> 4
41284559 if (src_abi_size > 4) {
4129 try self.asmRegisterImmediate(.mov, imm, imm_0000_1111);
4130 try self.asmRegisterRegister(.@"and", tmp, imm);
4131 try self.asmRegisterRegister(.@"and", dst, imm);
4560 try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_0000_1111);
4561 try self.asmRegisterRegister(.{ ._, .@"and" }, tmp, imm);
4562 try self.asmRegisterRegister(.{ ._, .@"and" }, dst, imm);
41324563 } else {
4133 try self.asmRegisterImmediate(.@"and", tmp, imm_0000_1111);
4134 try self.asmRegisterImmediate(.@"and", dst, imm_0000_1111);
4564 try self.asmRegisterImmediate(.{ ._, .@"and" }, tmp, imm_0000_1111);
4565 try self.asmRegisterImmediate(.{ ._, .@"and" }, dst, imm_0000_1111);
41354566 }
41364567 // tmp = temp1 & 0x0F...0F
41374568 // dst = (temp1 >> 4) & 0x0F...0F
4138 try self.asmRegisterImmediate(.shl, tmp, Immediate.u(4));
4569 try self.asmRegisterImmediate(.{ ._l, .sh }, tmp, Immediate.u(4));
41394570 // tmp = (temp1 & 0x0F...0F) << 4
4140 try self.asmRegisterRegister(.@"or", dst, tmp);
4571 try self.asmRegisterRegister(.{ ._, .@"or" }, dst, tmp);
41414572 // dst = temp2 = ((temp1 >> 4) & 0x0F...0F) | ((temp1 & 0x0F...0F) << 4)
4142 try self.asmRegisterRegister(.mov, tmp, dst);
4573 try self.asmRegisterRegister(.{ ._, .mov }, tmp, dst);
41434574 // tmp = temp2
4144 try self.asmRegisterImmediate(.shr, dst, Immediate.u(2));
4575 try self.asmRegisterImmediate(.{ ._r, .sh }, dst, Immediate.u(2));
41454576 // dst = temp2 >> 2
41464577 if (src_abi_size > 4) {
4147 try self.asmRegisterImmediate(.mov, imm, imm_00_11);
4148 try self.asmRegisterRegister(.@"and", tmp, imm);
4149 try self.asmRegisterRegister(.@"and", dst, imm);
4578 try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_00_11);
4579 try self.asmRegisterRegister(.{ ._, .@"and" }, tmp, imm);
4580 try self.asmRegisterRegister(.{ ._, .@"and" }, dst, imm);
41504581 } else {
4151 try self.asmRegisterImmediate(.@"and", tmp, imm_00_11);
4152 try self.asmRegisterImmediate(.@"and", dst, imm_00_11);
4582 try self.asmRegisterImmediate(.{ ._, .@"and" }, tmp, imm_00_11);
4583 try self.asmRegisterImmediate(.{ ._, .@"and" }, dst, imm_00_11);
41534584 }
41544585 // tmp = temp2 & 0x33...33
41554586 // dst = (temp2 >> 2) & 0x33...33
41564587 try self.asmRegisterMemory(
4157 .lea,
4588 .{ ._, .lea },
41584589 if (src_abi_size > 4) tmp.to64() else tmp.to32(),
41594590 Memory.sib(.qword, .{
41604591 .base = .{ .reg = dst.to64() },
......@@ -4162,22 +4593,22 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
41624593 }),
41634594 );
41644595 // tmp = temp3 = ((temp2 >> 2) & 0x33...33) + ((temp2 & 0x33...33) << 2)
4165 try self.asmRegisterRegister(.mov, dst, tmp);
4596 try self.asmRegisterRegister(.{ ._, .mov }, dst, tmp);
41664597 // dst = temp3
4167 try self.asmRegisterImmediate(.shr, tmp, Immediate.u(1));
4598 try self.asmRegisterImmediate(.{ ._r, .sh }, tmp, Immediate.u(1));
41684599 // tmp = temp3 >> 1
41694600 if (src_abi_size > 4) {
4170 try self.asmRegisterImmediate(.mov, imm, imm_0_1);
4171 try self.asmRegisterRegister(.@"and", dst, imm);
4172 try self.asmRegisterRegister(.@"and", tmp, imm);
4601 try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_0_1);
4602 try self.asmRegisterRegister(.{ ._, .@"and" }, dst, imm);
4603 try self.asmRegisterRegister(.{ ._, .@"and" }, tmp, imm);
41734604 } else {
4174 try self.asmRegisterImmediate(.@"and", dst, imm_0_1);
4175 try self.asmRegisterImmediate(.@"and", tmp, imm_0_1);
4605 try self.asmRegisterImmediate(.{ ._, .@"and" }, dst, imm_0_1);
4606 try self.asmRegisterImmediate(.{ ._, .@"and" }, tmp, imm_0_1);
41764607 }
41774608 // dst = temp3 & 0x55...55
41784609 // tmp = (temp3 >> 1) & 0x55...55
41794610 try self.asmRegisterMemory(
4180 .lea,
4611 .{ ._, .lea },
41814612 if (src_abi_size > 4) dst.to64() else dst.to32(),
41824613 Memory.sib(.qword, .{
41834614 .base = .{ .reg = tmp.to64() },
......@@ -4190,7 +4621,7 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
41904621 switch (self.regExtraBits(src_ty)) {
41914622 0 => {},
41924623 else => |extra| try self.genBinOpMir(
4193 if (src_ty.isSignedInt()) .sar else .shr,
4624 if (src_ty.isSignedInt()) .{ ._r, .sa } else .{ ._r, .sh },
41944625 src_ty,
41954626 dst_mcv,
41964627 .{ .immediate = extra },
......@@ -4246,19 +4677,20 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {
42464677 const tag = self.air.instructions.items(.tag)[inst];
42474678 try self.genBinOpMir(switch (ty_bits) {
42484679 // No point using an extra prefix byte for *pd which performs the same operation.
4249 32, 64 => switch (tag) {
4250 .neg => .xorps,
4251 .fabs => .andnps,
4680 16, 32, 64, 128 => switch (tag) {
4681 .neg => .{ ._ps, .xor },
4682 .fabs => .{ ._ps, .andn },
42524683 else => unreachable,
42534684 },
4254 else => return self.fail("TODO implement airFloatSign for {}", .{
4685 80 => return self.fail("TODO implement airFloatSign for {}", .{
42554686 ty.fmt(self.bin_file.options.module.?),
42564687 }),
4688 else => unreachable,
42574689 }, vec_ty, dst_mcv, sign_mcv);
42584690 return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none });
42594691}
42604692
4261fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
4693fn airRound(self: *Self, inst: Air.Inst.Index, mode: u4) !void {
42624694 const un_op = self.air.instructions.items(.data)[inst].un_op;
42634695 const ty = self.air.typeOf(un_op);
42644696
......@@ -4267,40 +4699,246 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
42674699 src_mcv
42684700 else
42694701 try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
4270
4271 try self.genBinOpMir(switch (ty.zigTypeTag()) {
4272 .Float => switch (ty.floatBits(self.target.*)) {
4273 32 => .sqrtss,
4274 64 => .sqrtsd,
4275 else => return self.fail("TODO implement airSqrt for {}", .{
4276 ty.fmt(self.bin_file.options.module.?),
4277 }),
4278 },
4279 else => return self.fail("TODO implement airSqrt for {}", .{
4280 ty.fmt(self.bin_file.options.module.?),
4281 }),
4282 }, ty, dst_mcv, src_mcv);
4702 const dst_reg = dst_mcv.getReg().?;
4703 const dst_lock = self.register_manager.lockReg(dst_reg);
4704 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
4705 try self.genRound(ty, dst_reg, src_mcv, mode);
42834706 return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none });
42844707}
42854708
4286fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {
4287 const un_op = self.air.instructions.items(.data)[inst].un_op;
4288 _ = un_op;
4289 return self.fail("TODO implement airUnaryMath for {}", .{
4290 self.air.instructions.items(.tag)[inst],
4291 });
4292 //return self.finishAir(inst, result, .{ un_op, .none, .none });
4293}
4709fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4) !void {
4710 if (!self.hasFeature(.sse4_1))
4711 return self.fail("TODO implement genRound without sse4_1 feature", .{});
42944712
4295fn reuseOperand(
4296 self: *Self,
4297 inst: Air.Inst.Index,
4298 operand: Air.Inst.Ref,
4299 op_index: Liveness.OperandInt,
4300 mcv: MCValue,
4301) bool {
4302 return self.reuseOperandAdvanced(inst, operand, op_index, mcv, inst);
4303}
4713 const mir_tag = if (@as(?Mir.Inst.FixedTag, switch (ty.zigTypeTag()) {
4714 .Float => switch (ty.floatBits(self.target.*)) {
4715 32 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round },
4716 64 => if (self.hasFeature(.avx)) .{ .v_sd, .round } else .{ ._sd, .round },
4717 16, 80, 128 => null,
4718 else => unreachable,
4719 },
4720 .Vector => switch (ty.childType().zigTypeTag()) {
4721 .Float => switch (ty.childType().floatBits(self.target.*)) {
4722 32 => switch (ty.vectorLen()) {
4723 1 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round },
4724 2...4 => if (self.hasFeature(.avx)) .{ .v_ps, .round } else .{ ._ps, .round },
4725 5...8 => if (self.hasFeature(.avx)) .{ .v_ps, .round } else null,
4726 else => null,
4727 },
4728 64 => switch (ty.vectorLen()) {
4729 1 => if (self.hasFeature(.avx)) .{ .v_sd, .round } else .{ ._sd, .round },
4730 2 => if (self.hasFeature(.avx)) .{ .v_pd, .round } else .{ ._pd, .round },
4731 3...4 => if (self.hasFeature(.avx)) .{ .v_pd, .round } else null,
4732 else => null,
4733 },
4734 16, 80, 128 => null,
4735 else => unreachable,
4736 },
4737 else => null,
4738 },
4739 else => unreachable,
4740 })) |tag| tag else return self.fail("TODO implement genRound for {}", .{
4741 ty.fmt(self.bin_file.options.module.?),
4742 });
4743
4744 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
4745 const dst_alias = registerAlias(dst_reg, abi_size);
4746 switch (mir_tag[0]) {
4747 .v_ss, .v_sd => if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(
4748 mir_tag,
4749 dst_alias,
4750 dst_alias,
4751 src_mcv.mem(Memory.PtrSize.fromSize(abi_size)),
4752 Immediate.u(mode),
4753 ) else try self.asmRegisterRegisterRegisterImmediate(
4754 mir_tag,
4755 dst_alias,
4756 dst_alias,
4757 registerAlias(if (src_mcv.isRegister())
4758 src_mcv.getReg().?
4759 else
4760 try self.copyToTmpRegister(ty, src_mcv), abi_size),
4761 Immediate.u(mode),
4762 ),
4763 else => if (src_mcv.isMemory()) try self.asmRegisterMemoryImmediate(
4764 mir_tag,
4765 dst_alias,
4766 src_mcv.mem(Memory.PtrSize.fromSize(abi_size)),
4767 Immediate.u(mode),
4768 ) else try self.asmRegisterRegisterImmediate(
4769 mir_tag,
4770 dst_alias,
4771 registerAlias(if (src_mcv.isRegister())
4772 src_mcv.getReg().?
4773 else
4774 try self.copyToTmpRegister(ty, src_mcv), abi_size),
4775 Immediate.u(mode),
4776 ),
4777 }
4778}
4779
4780fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
4781 const un_op = self.air.instructions.items(.data)[inst].un_op;
4782 const ty = self.air.typeOf(un_op);
4783 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
4784
4785 const src_mcv = try self.resolveInst(un_op);
4786 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv))
4787 src_mcv
4788 else
4789 try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
4790 const dst_reg = registerAlias(dst_mcv.getReg().?, abi_size);
4791 const dst_lock = self.register_manager.lockReg(dst_reg);
4792 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
4793
4794 const result: MCValue = result: {
4795 const mir_tag = if (@as(?Mir.Inst.FixedTag, switch (ty.zigTypeTag()) {
4796 .Float => switch (ty.floatBits(self.target.*)) {
4797 16 => if (self.hasFeature(.f16c)) {
4798 const mat_src_reg = if (src_mcv.isRegister())
4799 src_mcv.getReg().?
4800 else
4801 try self.copyToTmpRegister(ty, src_mcv);
4802 try self.asmRegisterRegister(.{ .v_, .cvtph2ps }, dst_reg, mat_src_reg.to128());
4803 try self.asmRegisterRegisterRegister(.{ .v_ss, .sqrt }, dst_reg, dst_reg, dst_reg);
4804 try self.asmRegisterRegisterImmediate(
4805 .{ .v_, .cvtps2ph },
4806 dst_reg,
4807 dst_reg,
4808 Immediate.u(0b1_00),
4809 );
4810 break :result dst_mcv;
4811 } else null,
4812 32 => if (self.hasFeature(.avx)) .{ .v_ss, .sqrt } else .{ ._ss, .sqrt },
4813 64 => if (self.hasFeature(.avx)) .{ .v_sd, .sqrt } else .{ ._sd, .sqrt },
4814 80, 128 => null,
4815 else => unreachable,
4816 },
4817 .Vector => switch (ty.childType().zigTypeTag()) {
4818 .Float => switch (ty.childType().floatBits(self.target.*)) {
4819 16 => if (self.hasFeature(.f16c)) switch (ty.vectorLen()) {
4820 1 => {
4821 try self.asmRegisterRegister(
4822 .{ .v_, .cvtph2ps },
4823 dst_reg,
4824 (if (src_mcv.isRegister())
4825 src_mcv.getReg().?
4826 else
4827 try self.copyToTmpRegister(ty, src_mcv)).to128(),
4828 );
4829 try self.asmRegisterRegisterRegister(
4830 .{ .v_ss, .sqrt },
4831 dst_reg,
4832 dst_reg,
4833 dst_reg,
4834 );
4835 try self.asmRegisterRegisterImmediate(
4836 .{ .v_, .cvtps2ph },
4837 dst_reg,
4838 dst_reg,
4839 Immediate.u(0b1_00),
4840 );
4841 break :result dst_mcv;
4842 },
4843 2...8 => {
4844 const wide_reg = registerAlias(dst_reg, abi_size * 2);
4845 if (src_mcv.isMemory()) try self.asmRegisterMemory(
4846 .{ .v_, .cvtph2ps },
4847 wide_reg,
4848 src_mcv.mem(Memory.PtrSize.fromSize(
4849 @intCast(u32, @divExact(wide_reg.bitSize(), 16)),
4850 )),
4851 ) else try self.asmRegisterRegister(
4852 .{ .v_, .cvtph2ps },
4853 wide_reg,
4854 (if (src_mcv.isRegister())
4855 src_mcv.getReg().?
4856 else
4857 try self.copyToTmpRegister(ty, src_mcv)).to128(),
4858 );
4859 try self.asmRegisterRegister(.{ .v_ps, .sqrt }, wide_reg, wide_reg);
4860 try self.asmRegisterRegisterImmediate(
4861 .{ .v_, .cvtps2ph },
4862 dst_reg,
4863 wide_reg,
4864 Immediate.u(0b1_00),
4865 );
4866 break :result dst_mcv;
4867 },
4868 else => null,
4869 } else null,
4870 32 => switch (ty.vectorLen()) {
4871 1 => if (self.hasFeature(.avx)) .{ .v_ss, .sqrt } else .{ ._ss, .sqrt },
4872 2...4 => if (self.hasFeature(.avx)) .{ .v_ps, .sqrt } else .{ ._ps, .sqrt },
4873 5...8 => if (self.hasFeature(.avx)) .{ .v_ps, .sqrt } else null,
4874 else => null,
4875 },
4876 64 => switch (ty.vectorLen()) {
4877 1 => if (self.hasFeature(.avx)) .{ .v_sd, .sqrt } else .{ ._sd, .sqrt },
4878 2 => if (self.hasFeature(.avx)) .{ .v_pd, .sqrt } else .{ ._pd, .sqrt },
4879 3...4 => if (self.hasFeature(.avx)) .{ .v_pd, .sqrt } else null,
4880 else => null,
4881 },
4882 80, 128 => null,
4883 else => unreachable,
4884 },
4885 else => unreachable,
4886 },
4887 else => unreachable,
4888 })) |tag| tag else return self.fail("TODO implement airSqrt for {}", .{
4889 ty.fmt(self.bin_file.options.module.?),
4890 });
4891 switch (mir_tag[0]) {
4892 .v_ss, .v_sd => if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
4893 mir_tag,
4894 dst_reg,
4895 dst_reg,
4896 src_mcv.mem(Memory.PtrSize.fromSize(abi_size)),
4897 ) else try self.asmRegisterRegisterRegister(
4898 mir_tag,
4899 dst_reg,
4900 dst_reg,
4901 registerAlias(if (src_mcv.isRegister())
4902 src_mcv.getReg().?
4903 else
4904 try self.copyToTmpRegister(ty, src_mcv), abi_size),
4905 ),
4906 else => if (src_mcv.isMemory()) try self.asmRegisterMemory(
4907 mir_tag,
4908 dst_reg,
4909 src_mcv.mem(Memory.PtrSize.fromSize(abi_size)),
4910 ) else try self.asmRegisterRegister(
4911 mir_tag,
4912 dst_reg,
4913 registerAlias(if (src_mcv.isRegister())
4914 src_mcv.getReg().?
4915 else
4916 try self.copyToTmpRegister(ty, src_mcv), abi_size),
4917 ),
4918 }
4919 break :result dst_mcv;
4920 };
4921 return self.finishAir(inst, result, .{ un_op, .none, .none });
4922}
4923
4924fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {
4925 const un_op = self.air.instructions.items(.data)[inst].un_op;
4926 _ = un_op;
4927 return self.fail("TODO implement airUnaryMath for {}", .{
4928 self.air.instructions.items(.tag)[inst],
4929 });
4930 //return self.finishAir(inst, result, .{ un_op, .none, .none });
4931}
4932
4933fn reuseOperand(
4934 self: *Self,
4935 inst: Air.Inst.Index,
4936 operand: Air.Inst.Ref,
4937 op_index: Liveness.OperandInt,
4938 mcv: MCValue,
4939) bool {
4940 return self.reuseOperandAdvanced(inst, operand, op_index, mcv, inst);
4941}
43044942
43054943fn reuseOperandAdvanced(
43064944 self: *Self,
......@@ -4366,14 +5004,14 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn
43665004 if (load_abi_size <= 8) {
43675005 const load_reg = registerAlias(dst_reg, load_abi_size);
43685006 try self.asmRegisterMemory(
4369 .mov,
5007 .{ ._, .mov },
43705008 load_reg,
43715009 Memory.sib(Memory.PtrSize.fromSize(load_abi_size), .{
43725010 .base = .{ .reg = ptr_reg },
43735011 .disp = val_byte_off,
43745012 }),
43755013 );
4376 try self.asmRegisterImmediate(.shr, load_reg, Immediate.u(val_bit_off));
5014 try self.asmRegisterImmediate(.{ ._r, .sh }, load_reg, Immediate.u(val_bit_off));
43775015 } else {
43785016 const tmp_reg = registerAlias(try self.register_manager.allocReg(null, gp), val_abi_size);
43795017 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
......@@ -4381,7 +5019,7 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn
43815019
43825020 const dst_alias = registerAlias(dst_reg, val_abi_size);
43835021 try self.asmRegisterMemory(
4384 .mov,
5022 .{ ._, .mov },
43855023 dst_alias,
43865024 Memory.sib(Memory.PtrSize.fromSize(val_abi_size), .{
43875025 .base = .{ .reg = ptr_reg },
......@@ -4389,14 +5027,19 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn
43895027 }),
43905028 );
43915029 try self.asmRegisterMemory(
4392 .mov,
5030 .{ ._, .mov },
43935031 tmp_reg,
43945032 Memory.sib(Memory.PtrSize.fromSize(val_abi_size), .{
43955033 .base = .{ .reg = ptr_reg },
43965034 .disp = val_byte_off + 1,
43975035 }),
43985036 );
4399 try self.asmRegisterRegisterImmediate(.shrd, dst_alias, tmp_reg, Immediate.u(val_bit_off));
5037 try self.asmRegisterRegisterImmediate(
5038 .{ ._rd, .sh },
5039 dst_alias,
5040 tmp_reg,
5041 Immediate.u(val_bit_off),
5042 );
44005043 }
44015044
44025045 if (val_extra_bits > 0) try self.truncateRegister(val_ty, dst_reg);
......@@ -4502,13 +5145,13 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In
45025145 const part_mask_not = part_mask ^
45035146 (@as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - limb_abi_bits));
45045147 if (limb_abi_size <= 4) {
4505 try self.asmMemoryImmediate(.@"and", limb_mem, Immediate.u(part_mask_not));
5148 try self.asmMemoryImmediate(.{ ._, .@"and" }, limb_mem, Immediate.u(part_mask_not));
45065149 } else if (math.cast(i32, @bitCast(i64, part_mask_not))) |small| {
4507 try self.asmMemoryImmediate(.@"and", limb_mem, Immediate.s(small));
5150 try self.asmMemoryImmediate(.{ ._, .@"and" }, limb_mem, Immediate.s(small));
45085151 } else {
45095152 const part_mask_reg = try self.register_manager.allocReg(null, gp);
4510 try self.asmRegisterImmediate(.mov, part_mask_reg, Immediate.u(part_mask_not));
4511 try self.asmMemoryRegister(.@"and", limb_mem, part_mask_reg);
5153 try self.asmRegisterImmediate(.{ ._, .mov }, part_mask_reg, Immediate.u(part_mask_not));
5154 try self.asmMemoryRegister(.{ ._, .@"and" }, limb_mem, part_mask_reg);
45125155 }
45135156
45145157 if (src_bit_size <= 64) {
......@@ -4519,14 +5162,26 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In
45195162
45205163 try self.genSetReg(tmp_reg, src_ty, src_mcv);
45215164 switch (limb_i) {
4522 0 => try self.genShiftBinOpMir(.shl, src_ty, tmp_mcv, .{ .immediate = src_bit_off }),
4523 1 => try self.genShiftBinOpMir(.shr, src_ty, tmp_mcv, .{
4524 .immediate = limb_abi_bits - src_bit_off,
4525 }),
5165 0 => try self.genShiftBinOpMir(
5166 .{ ._l, .sh },
5167 src_ty,
5168 tmp_mcv,
5169 .{ .immediate = src_bit_off },
5170 ),
5171 1 => try self.genShiftBinOpMir(
5172 .{ ._r, .sh },
5173 src_ty,
5174 tmp_mcv,
5175 .{ .immediate = limb_abi_bits - src_bit_off },
5176 ),
45265177 else => unreachable,
45275178 }
4528 try self.genBinOpMir(.@"and", src_ty, tmp_mcv, .{ .immediate = part_mask });
4529 try self.asmMemoryRegister(.@"or", limb_mem, registerAlias(tmp_reg, limb_abi_size));
5179 try self.genBinOpMir(.{ ._, .@"and" }, src_ty, tmp_mcv, .{ .immediate = part_mask });
5180 try self.asmMemoryRegister(
5181 .{ ._, .@"or" },
5182 limb_mem,
5183 registerAlias(tmp_reg, limb_abi_size),
5184 );
45305185 } else return self.fail("TODO: implement packed store of {}", .{
45315186 src_ty.fmt(self.bin_file.options.module.?),
45325187 });
......@@ -4626,7 +5281,7 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32
46265281 .load_tlv => |sym_index| .{ .lea_tlv = sym_index },
46275282 else => mcv,
46285283 });
4629 try self.genBinOpMir(.add, Type.usize, dst_mcv, .{ .register = offset_reg });
5284 try self.genBinOpMir(.{ ._, .add }, Type.usize, dst_mcv, .{ .register = offset_reg });
46305285 break :result dst_mcv;
46315286 },
46325287 .indirect => |reg_off| break :result .{ .indirect = .{
......@@ -4710,14 +5365,14 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
47105365 if (load_abi_size <= 8) {
47115366 const load_reg = registerAlias(dst_reg, load_abi_size);
47125367 try self.asmRegisterMemory(
4713 .mov,
5368 .{ ._, .mov },
47145369 load_reg,
47155370 Memory.sib(Memory.PtrSize.fromSize(load_abi_size), .{
47165371 .base = .{ .frame = frame_addr.index },
47175372 .disp = frame_addr.off + field_byte_off,
47185373 }),
47195374 );
4720 try self.asmRegisterImmediate(.shr, load_reg, Immediate.u(field_bit_off));
5375 try self.asmRegisterImmediate(.{ ._r, .sh }, load_reg, Immediate.u(field_bit_off));
47215376 } else {
47225377 const tmp_reg = registerAlias(
47235378 try self.register_manager.allocReg(null, gp),
......@@ -4728,7 +5383,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
47285383
47295384 const dst_alias = registerAlias(dst_reg, field_abi_size);
47305385 try self.asmRegisterMemory(
4731 .mov,
5386 .{ ._, .mov },
47325387 dst_alias,
47335388 Memory.sib(Memory.PtrSize.fromSize(field_abi_size), .{
47345389 .base = .{ .frame = frame_addr.index },
......@@ -4736,7 +5391,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
47365391 }),
47375392 );
47385393 try self.asmRegisterMemory(
4739 .mov,
5394 .{ ._, .mov },
47405395 tmp_reg,
47415396 Memory.sib(Memory.PtrSize.fromSize(field_abi_size), .{
47425397 .base = .{ .frame = frame_addr.index },
......@@ -4744,7 +5399,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
47445399 }),
47455400 );
47465401 try self.asmRegisterRegisterImmediate(
4747 .shrd,
5402 .{ ._rd, .sh },
47485403 dst_alias,
47495404 tmp_reg,
47505405 Immediate.u(field_bit_off),
......@@ -4752,7 +5407,14 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
47525407 }
47535408
47545409 if (field_extra_bits > 0) try self.truncateRegister(field_ty, dst_reg);
4755 break :result .{ .register = dst_reg };
5410
5411 const dst_mcv = MCValue{ .register = dst_reg };
5412 const dst_rc = regClassForType(field_ty);
5413 if (dst_rc.eql(gp)) break :result dst_mcv;
5414
5415 const result_reg = try self.register_manager.allocReg(inst, dst_rc);
5416 try self.genSetReg(result_reg, field_ty, dst_mcv);
5417 break :result .{ .register = result_reg };
47565418 },
47575419 .register => |reg| {
47585420 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
......@@ -4773,21 +5435,26 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
47735435 defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
47745436
47755437 // Shift by struct_field_offset.
4776 try self.genShiftBinOpMir(.shr, Type.usize, dst_mcv, .{ .immediate = field_off });
5438 try self.genShiftBinOpMir(
5439 .{ ._r, .sh },
5440 Type.usize,
5441 dst_mcv,
5442 .{ .immediate = field_off },
5443 );
47775444
47785445 // Mask to field_bit_size bits
47795446 const field_bit_size = field_ty.bitSize(self.target.*);
47805447 const mask = ~@as(u64, 0) >> @intCast(u6, 64 - field_bit_size);
47815448
47825449 const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask });
4783 try self.genBinOpMir(.@"and", Type.usize, dst_mcv, .{ .register = tmp_reg });
5450 try self.genBinOpMir(.{ ._, .@"and" }, Type.usize, dst_mcv, .{ .register = tmp_reg });
47845451
47855452 const signedness =
47865453 if (field_ty.isAbiInt()) field_ty.intInfo(self.target.*).signedness else .unsigned;
47875454 const field_byte_size = @intCast(u32, field_ty.abiSize(self.target.*));
47885455 if (signedness == .signed and field_byte_size < 8) {
47895456 try self.asmRegisterRegister(
4790 .movsx,
5457 if (field_byte_size >= 4) .{ ._d, .movsx } else .{ ._, .movsx },
47915458 dst_mcv.register,
47925459 registerAlias(dst_mcv.register, field_byte_size),
47935460 );
......@@ -4899,17 +5566,17 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:
48995566
49005567 if (limb_pl.base.tag == .int_unsigned and self.regExtraBits(limb_ty) > 0) {
49015568 const mask = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - limb_pl.data);
4902 try self.genBinOpMir(.xor, limb_ty, limb_mcv, .{ .immediate = mask });
4903 } else try self.genUnOpMir(.not, limb_ty, limb_mcv);
5569 try self.genBinOpMir(.{ ._, .xor }, limb_ty, limb_mcv, .{ .immediate = mask });
5570 } else try self.genUnOpMir(.{ ._, .not }, limb_ty, limb_mcv);
49045571 }
49055572 },
4906 .neg => try self.genUnOpMir(.neg, src_ty, dst_mcv),
5573 .neg => try self.genUnOpMir(.{ ._, .neg }, src_ty, dst_mcv),
49075574 else => unreachable,
49085575 }
49095576 return dst_mcv;
49105577}
49115578
4912fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue) !void {
5579fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MCValue) !void {
49135580 const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
49145581 if (abi_size > 8) return self.fail("TODO implement {} for {}", .{
49155582 mir_tag,
......@@ -4952,7 +5619,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue
49525619/// Clobbers .rcx for non-immediate shift value.
49535620fn genShiftBinOpMir(
49545621 self: *Self,
4955 tag: Mir.Inst.Tag,
5622 tag: Mir.Inst.FixedTag,
49565623 ty: Type,
49575624 lhs_mcv: MCValue,
49585625 shift_mcv: MCValue,
......@@ -5037,16 +5704,16 @@ fn genShiftBinOpMir(
50375704 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
50385705 defer self.register_manager.unlockReg(tmp_lock);
50395706
5040 const info: struct { offsets: [2]i32, double_tag: Mir.Inst.Tag } = switch (tag) {
5041 .shl, .sal => .{ .offsets = .{ 0, 8 }, .double_tag = .shld },
5042 .shr, .sar => .{ .offsets = .{ 8, 0 }, .double_tag = .shrd },
5707 const info: struct { offsets: [2]i32, double_tag: Mir.Inst.FixedTag } = switch (tag[0]) {
5708 ._l => .{ .offsets = .{ 0, 8 }, .double_tag = .{ ._ld, .sh } },
5709 ._r => .{ .offsets = .{ 8, 0 }, .double_tag = .{ ._rd, .sh } },
50435710 else => unreachable,
50445711 };
50455712 switch (lhs_mcv) {
50465713 .load_frame => |dst_frame_addr| switch (rhs_mcv) {
50475714 .immediate => |rhs_imm| if (rhs_imm == 0) {} else if (rhs_imm < 64) {
50485715 try self.asmRegisterMemory(
5049 .mov,
5716 .{ ._, .mov },
50505717 tmp_reg,
50515718 Memory.sib(.qword, .{
50525719 .base = .{ .frame = dst_frame_addr.index },
......@@ -5073,7 +5740,7 @@ fn genShiftBinOpMir(
50735740 } else {
50745741 assert(rhs_imm < 128);
50755742 try self.asmRegisterMemory(
5076 .mov,
5743 .{ ._, .mov },
50775744 tmp_reg,
50785745 Memory.sib(.qword, .{
50795746 .base = .{ .frame = dst_frame_addr.index },
......@@ -5084,34 +5751,30 @@ fn genShiftBinOpMir(
50845751 try self.asmRegisterImmediate(tag, tmp_reg, Immediate.u(rhs_imm - 64));
50855752 }
50865753 try self.asmMemoryRegister(
5087 .mov,
5754 .{ ._, .mov },
50885755 Memory.sib(.qword, .{
50895756 .base = .{ .frame = dst_frame_addr.index },
50905757 .disp = dst_frame_addr.off + info.offsets[1],
50915758 }),
50925759 tmp_reg,
50935760 );
5094 switch (tag) {
5095 .shl, .sal, .shr => {
5096 try self.asmRegisterRegister(.xor, tmp_reg.to32(), tmp_reg.to32());
5097 try self.asmMemoryRegister(
5098 .mov,
5099 Memory.sib(.qword, .{
5100 .base = .{ .frame = dst_frame_addr.index },
5101 .disp = dst_frame_addr.off + info.offsets[0],
5102 }),
5103 tmp_reg,
5104 );
5105 },
5106 .sar => try self.asmMemoryImmediate(
5107 tag,
5761 if (tag[0] == ._r and tag[1] == .sa) try self.asmMemoryImmediate(
5762 tag,
5763 Memory.sib(.qword, .{
5764 .base = .{ .frame = dst_frame_addr.index },
5765 .disp = dst_frame_addr.off + info.offsets[0],
5766 }),
5767 Immediate.u(63),
5768 ) else {
5769 try self.asmRegisterRegister(.{ ._, .xor }, tmp_reg.to32(), tmp_reg.to32());
5770 try self.asmMemoryRegister(
5771 .{ ._, .mov },
51085772 Memory.sib(.qword, .{
51095773 .base = .{ .frame = dst_frame_addr.index },
51105774 .disp = dst_frame_addr.off + info.offsets[0],
51115775 }),
5112 Immediate.u(63),
5113 ),
5114 else => unreachable,
5776 tmp_reg,
5777 );
51155778 }
51165779 },
51175780 else => {
......@@ -5125,7 +5788,7 @@ fn genShiftBinOpMir(
51255788
51265789 try self.genSetReg(.cl, Type.u8, rhs_mcv);
51275790 try self.asmRegisterMemory(
5128 .mov,
5791 .{ ._, .mov },
51295792 first_reg,
51305793 Memory.sib(.qword, .{
51315794 .base = .{ .frame = dst_frame_addr.index },
......@@ -5133,32 +5796,28 @@ fn genShiftBinOpMir(
51335796 }),
51345797 );
51355798 try self.asmRegisterMemory(
5136 .mov,
5799 .{ ._, .mov },
51375800 second_reg,
51385801 Memory.sib(.qword, .{
51395802 .base = .{ .frame = dst_frame_addr.index },
51405803 .disp = dst_frame_addr.off + info.offsets[1],
51415804 }),
51425805 );
5143 switch (tag) {
5144 .shl, .sal, .shr => try self.asmRegisterRegister(
5145 .xor,
5146 tmp_reg.to32(),
5147 tmp_reg.to32(),
5148 ),
5149 .sar => {
5150 try self.asmRegisterRegister(.mov, tmp_reg, first_reg);
5151 try self.asmRegisterImmediate(tag, tmp_reg, Immediate.u(63));
5152 },
5153 else => unreachable,
5154 }
5806 if (tag[0] == ._r and tag[1] == .sa) {
5807 try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, first_reg);
5808 try self.asmRegisterImmediate(tag, tmp_reg, Immediate.u(63));
5809 } else try self.asmRegisterRegister(
5810 .{ ._, .xor },
5811 tmp_reg.to32(),
5812 tmp_reg.to32(),
5813 );
51555814 try self.asmRegisterRegisterRegister(info.double_tag, second_reg, first_reg, .cl);
51565815 try self.asmRegisterRegister(tag, first_reg, .cl);
5157 try self.asmRegisterImmediate(.cmp, .cl, Immediate.u(64));
5816 try self.asmRegisterImmediate(.{ ._, .cmp }, .cl, Immediate.u(64));
51585817 try self.asmCmovccRegisterRegister(second_reg, first_reg, .ae);
51595818 try self.asmCmovccRegisterRegister(first_reg, tmp_reg, .ae);
51605819 try self.asmMemoryRegister(
5161 .mov,
5820 .{ ._, .mov },
51625821 Memory.sib(.qword, .{
51635822 .base = .{ .frame = dst_frame_addr.index },
51645823 .disp = dst_frame_addr.off + info.offsets[1],
......@@ -5166,7 +5825,7 @@ fn genShiftBinOpMir(
51665825 second_reg,
51675826 );
51685827 try self.asmMemoryRegister(
5169 .mov,
5828 .{ ._, .mov },
51705829 Memory.sib(.qword, .{
51715830 .base = .{ .frame = dst_frame_addr.index },
51725831 .disp = dst_frame_addr.off + info.offsets[0],
......@@ -5191,7 +5850,7 @@ fn genShiftBinOpMir(
51915850/// Asserts .rcx is free.
51925851fn genShiftBinOp(
51935852 self: *Self,
5194 tag: Air.Inst.Tag,
5853 air_tag: Air.Inst.Tag,
51955854 maybe_inst: ?Air.Inst.Index,
51965855 lhs_mcv: MCValue,
51975856 rhs_mcv: MCValue,
......@@ -5236,14 +5895,14 @@ fn genShiftBinOp(
52365895 };
52375896
52385897 const signedness = lhs_ty.intInfo(self.target.*).signedness;
5239 try self.genShiftBinOpMir(switch (tag) {
5898 try self.genShiftBinOpMir(switch (air_tag) {
52405899 .shl, .shl_exact => switch (signedness) {
5241 .signed => .sal,
5242 .unsigned => .shl,
5900 .signed => .{ ._l, .sa },
5901 .unsigned => .{ ._l, .sh },
52435902 },
52445903 .shr, .shr_exact => switch (signedness) {
5245 .signed => .sar,
5246 .unsigned => .shr,
5904 .signed => .{ ._r, .sa },
5905 .unsigned => .{ ._r, .sh },
52475906 },
52485907 else => unreachable,
52495908 }, lhs_ty, dst_mcv, rhs_mcv);
......@@ -5303,20 +5962,18 @@ fn genMulDivBinOp(
53035962 try self.register_manager.getReg(.rax, track_inst_rax);
53045963 try self.register_manager.getReg(.rdx, track_inst_rdx);
53055964
5306 const mir_tag: Mir.Inst.Tag = switch (signedness) {
5965 try self.genIntMulDivOpMir(switch (signedness) {
53075966 .signed => switch (tag) {
5308 .mul, .mulwrap => .imul,
5309 .div_trunc, .div_exact, .rem => .idiv,
5967 .mul, .mulwrap => .{ .i_, .mul },
5968 .div_trunc, .div_exact, .rem => .{ .i_, .div },
53105969 else => unreachable,
53115970 },
53125971 .unsigned => switch (tag) {
5313 .mul, .mulwrap => .mul,
5314 .div_trunc, .div_exact, .rem => .div,
5972 .mul, .mulwrap => .{ ._, .mul },
5973 .div_trunc, .div_exact, .rem => .{ ._, .div },
53155974 else => unreachable,
53165975 },
5317 };
5318
5319 try self.genIntMulDivOpMir(mir_tag, ty, lhs, rhs);
5976 }, ty, lhs, rhs);
53205977
53215978 if (dst_abi_size <= 8) return .{ .register = registerAlias(switch (tag) {
53225979 .mul, .mulwrap, .div_trunc, .div_exact => .rax,
......@@ -5326,7 +5983,7 @@ fn genMulDivBinOp(
53265983
53275984 const dst_mcv = try self.allocRegOrMemAdvanced(dst_ty, maybe_inst, false);
53285985 try self.asmMemoryRegister(
5329 .mov,
5986 .{ ._, .mov },
53305987 Memory.sib(.qword, .{
53315988 .base = .{ .frame = dst_mcv.load_frame.index },
53325989 .disp = dst_mcv.load_frame.off,
......@@ -5334,7 +5991,7 @@ fn genMulDivBinOp(
53345991 .rax,
53355992 );
53365993 try self.asmMemoryRegister(
5337 .mov,
5994 .{ ._, .mov },
53385995 Memory.sib(.qword, .{
53395996 .base = .{ .frame = dst_mcv.load_frame.index },
53405997 .disp = dst_mcv.load_frame.off + 8,
......@@ -5375,12 +6032,12 @@ fn genMulDivBinOp(
53756032 try self.copyToRegisterWithInstTracking(inst, ty, lhs)
53766033 else
53776034 .{ .register = try self.copyToTmpRegister(ty, lhs) };
5378 try self.genBinOpMir(.sub, ty, result, div_floor);
6035 try self.genBinOpMir(.{ ._, .sub }, ty, result, div_floor);
53796036
53806037 return result;
53816038 },
53826039 .unsigned => {
5383 try self.genIntMulDivOpMir(.div, ty, lhs, rhs);
6040 try self.genIntMulDivOpMir(.{ ._, .div }, ty, lhs, rhs);
53846041 return .{ .register = registerAlias(.rdx, abi_size) };
53856042 },
53866043 }
......@@ -5422,7 +6079,7 @@ fn genMulDivBinOp(
54226079 switch (signedness) {
54236080 .signed => return try self.genInlineIntDivFloor(ty, lhs, actual_rhs),
54246081 .unsigned => {
5425 try self.genIntMulDivOpMir(.div, ty, lhs, actual_rhs);
6082 try self.genIntMulDivOpMir(.{ ._, .div }, ty, lhs, actual_rhs);
54266083 return .{ .register = registerAlias(.rax, abi_size) };
54276084 },
54286085 }
......@@ -5432,25 +6089,22 @@ fn genMulDivBinOp(
54326089 }
54336090}
54346091
5435/// Result is always a register.
54366092fn genBinOp(
54376093 self: *Self,
54386094 maybe_inst: ?Air.Inst.Index,
5439 tag: Air.Inst.Tag,
6095 air_tag: Air.Inst.Tag,
54406096 lhs_air: Air.Inst.Ref,
54416097 rhs_air: Air.Inst.Ref,
54426098) !MCValue {
5443 const lhs = try self.resolveInst(lhs_air);
5444 const rhs = try self.resolveInst(rhs_air);
6099 const lhs_mcv = try self.resolveInst(lhs_air);
6100 const rhs_mcv = try self.resolveInst(rhs_air);
54456101 const lhs_ty = self.air.typeOf(lhs_air);
54466102 const rhs_ty = self.air.typeOf(rhs_air);
5447 if (lhs_ty.zigTypeTag() == .Vector) {
5448 return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)});
5449 }
6103 const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
54506104
5451 switch (lhs) {
6105 switch (lhs_mcv) {
54526106 .immediate => |imm| switch (imm) {
5453 0 => switch (tag) {
6107 0 => switch (air_tag) {
54546108 .sub, .subwrap => return self.genUnOp(maybe_inst, .neg, rhs_air),
54556109 else => {},
54566110 },
......@@ -5459,9 +6113,10 @@ fn genBinOp(
54596113 else => {},
54606114 }
54616115
5462 const is_commutative = switch (tag) {
6116 const is_commutative = switch (air_tag) {
54636117 .add,
54646118 .addwrap,
6119 .mul,
54656120 .bool_or,
54666121 .bit_or,
54676122 .bool_and,
......@@ -5473,48 +6128,42 @@ fn genBinOp(
54736128
54746129 else => false,
54756130 };
5476 const dst_mem_ok = switch (tag) {
5477 .add,
5478 .addwrap,
5479 .sub,
5480 .subwrap,
5481 .mul,
5482 .div_float,
5483 .div_exact,
5484 .div_trunc,
5485 .div_floor,
5486 => !lhs_ty.isRuntimeFloat(),
5487
5488 else => true,
6131 const vec_op = switch (lhs_ty.zigTypeTag()) {
6132 else => false,
6133 .Float, .Vector => true,
54896134 };
54906135
5491 const lhs_lock: ?RegisterLock = switch (lhs) {
6136 const lhs_lock: ?RegisterLock = switch (lhs_mcv) {
54926137 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
54936138 else => null,
54946139 };
54956140 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
54966141
5497 const rhs_lock: ?RegisterLock = switch (rhs) {
6142 const rhs_lock: ?RegisterLock = switch (rhs_mcv) {
54986143 .register => |reg| self.register_manager.lockReg(reg),
54996144 else => null,
55006145 };
55016146 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
55026147
5503 var flipped: bool = false;
6148 var flipped = false;
6149 var copied_to_dst = true;
55046150 const dst_mcv: MCValue = dst: {
55056151 if (maybe_inst) |inst| {
5506 if ((dst_mem_ok or lhs.isRegister()) and self.reuseOperand(inst, lhs_air, 0, lhs)) {
5507 break :dst lhs;
6152 if ((!vec_op or lhs_mcv.isRegister()) and self.reuseOperand(inst, lhs_air, 0, lhs_mcv)) {
6153 break :dst lhs_mcv;
55086154 }
5509 if (is_commutative and (dst_mem_ok or rhs.isRegister()) and
5510 self.reuseOperand(inst, rhs_air, 1, rhs))
6155 if (is_commutative and (!vec_op or rhs_mcv.isRegister()) and
6156 self.reuseOperand(inst, rhs_air, 1, rhs_mcv))
55116157 {
55126158 flipped = true;
5513 break :dst rhs;
6159 break :dst rhs_mcv;
55146160 }
55156161 }
55166162 const dst_mcv = try self.allocRegOrMemAdvanced(lhs_ty, maybe_inst, true);
5517 try self.genCopy(lhs_ty, dst_mcv, lhs);
6163 if (vec_op and lhs_mcv.isRegister() and self.hasFeature(.avx))
6164 copied_to_dst = false
6165 else
6166 try self.genCopy(lhs_ty, dst_mcv, lhs_mcv);
55186167 break :dst dst_mcv;
55196168 };
55206169 const dst_lock: ?RegisterLock = switch (dst_mcv) {
......@@ -5523,160 +6172,52 @@ fn genBinOp(
55236172 };
55246173 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
55256174
5526 const src_mcv = if (flipped) lhs else rhs;
5527 switch (tag) {
5528 .add,
5529 .addwrap,
5530 => try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) {
5531 else => .add,
5532 .Float => switch (lhs_ty.floatBits(self.target.*)) {
5533 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse))
5534 .addss
5535 else
5536 return self.fail("TODO implement genBinOp for {s} {} without sse", .{
5537 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5538 }),
5539 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2))
5540 .addsd
5541 else
5542 return self.fail("TODO implement genBinOp for {s} {} without sse2", .{
5543 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5544 }),
5545 else => return self.fail("TODO implement genBinOp for {s} {}", .{
5546 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5547 }),
5548 },
5549 }, lhs_ty, dst_mcv, src_mcv),
5550
5551 .sub,
5552 .subwrap,
5553 => try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) {
5554 else => .sub,
5555 .Float => switch (lhs_ty.floatBits(self.target.*)) {
5556 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse))
5557 .subss
5558 else
5559 return self.fail("TODO implement genBinOp for {s} {} without sse", .{
5560 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5561 }),
5562 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2))
5563 .subsd
5564 else
5565 return self.fail("TODO implement genBinOp for {s} {} without sse2", .{
5566 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5567 }),
5568 else => return self.fail("TODO implement genBinOp for {s} {}", .{
5569 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5570 }),
5571 },
5572 }, lhs_ty, dst_mcv, src_mcv),
5573
5574 .mul => try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) {
5575 else => return self.fail("TODO implement genBinOp for {s} {}", .{
5576 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5577 }),
5578 .Float => switch (lhs_ty.floatBits(self.target.*)) {
5579 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse))
5580 .mulss
5581 else
5582 return self.fail("TODO implement genBinOp for {s} {} without sse", .{
5583 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5584 }),
5585 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2))
5586 .mulsd
5587 else
5588 return self.fail("TODO implement genBinOp for {s} {} without sse2", .{
5589 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5590 }),
5591 else => return self.fail("TODO implement genBinOp for {s} {}", .{
5592 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5593 }),
5594 },
5595 }, lhs_ty, dst_mcv, src_mcv),
6175 const src_mcv = if (flipped) lhs_mcv else rhs_mcv;
6176 if (!vec_op) {
6177 switch (air_tag) {
6178 .add,
6179 .addwrap,
6180 => try self.genBinOpMir(.{ ._, .add }, lhs_ty, dst_mcv, src_mcv),
55966181
5597 .div_float,
5598 .div_exact,
5599 .div_trunc,
5600 .div_floor,
5601 => {
5602 try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) {
5603 else => return self.fail("TODO implement genBinOp for {s} {}", .{
5604 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5605 }),
5606 .Float => switch (lhs_ty.floatBits(self.target.*)) {
5607 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse))
5608 .divss
5609 else
5610 return self.fail("TODO implement genBinOp for {s} {} without sse", .{
5611 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5612 }),
5613 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2))
5614 .divsd
5615 else
5616 return self.fail("TODO implement genBinOp for {s} {} without sse2", .{
5617 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5618 }),
5619 else => return self.fail("TODO implement genBinOp for {s} {}", .{
5620 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5621 }),
5622 },
5623 }, lhs_ty, dst_mcv, src_mcv);
5624 switch (tag) {
5625 .div_float,
5626 .div_exact,
5627 => {},
5628 .div_trunc,
5629 .div_floor,
5630 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse4_1)) {
5631 const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
5632 const dst_alias = registerAlias(dst_mcv.register, abi_size);
5633 try self.asmRegisterRegisterImmediate(switch (lhs_ty.floatBits(self.target.*)) {
5634 32 => .roundss,
5635 64 => .roundsd,
5636 else => unreachable,
5637 }, dst_alias, dst_alias, Immediate.u(switch (tag) {
5638 .div_trunc => 0b1_0_11,
5639 .div_floor => 0b1_0_01,
6182 .sub,
6183 .subwrap,
6184 => try self.genBinOpMir(.{ ._, .sub }, lhs_ty, dst_mcv, src_mcv),
6185
6186 .ptr_add,
6187 .ptr_sub,
6188 => {
6189 const tmp_reg = try self.copyToTmpRegister(rhs_ty, src_mcv);
6190 const tmp_mcv = MCValue{ .register = tmp_reg };
6191 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
6192 defer self.register_manager.unlockReg(tmp_lock);
6193
6194 const elem_size = lhs_ty.elemType2().abiSize(self.target.*);
6195 try self.genIntMulComplexOpMir(rhs_ty, tmp_mcv, .{ .immediate = elem_size });
6196 try self.genBinOpMir(
6197 switch (air_tag) {
6198 .ptr_add => .{ ._, .add },
6199 .ptr_sub => .{ ._, .sub },
56406200 else => unreachable,
5641 }));
5642 } else return self.fail("TODO implement genBinOp for {s} {} without sse4_1", .{
5643 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5644 }),
5645 else => unreachable,
5646 }
5647 },
5648
5649 .ptr_add,
5650 .ptr_sub,
5651 => {
5652 const tmp_reg = try self.copyToTmpRegister(rhs_ty, src_mcv);
5653 const tmp_mcv = MCValue{ .register = tmp_reg };
5654 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
5655 defer self.register_manager.unlockReg(tmp_lock);
5656
5657 const elem_size = lhs_ty.elemType2().abiSize(self.target.*);
5658 try self.genIntMulComplexOpMir(rhs_ty, tmp_mcv, .{ .immediate = elem_size });
5659 try self.genBinOpMir(switch (tag) {
5660 .ptr_add => .add,
5661 .ptr_sub => .sub,
5662 else => unreachable,
5663 }, lhs_ty, dst_mcv, tmp_mcv);
5664 },
6201 },
6202 lhs_ty,
6203 dst_mcv,
6204 tmp_mcv,
6205 );
6206 },
56656207
5666 .bool_or,
5667 .bit_or,
5668 => try self.genBinOpMir(.@"or", lhs_ty, dst_mcv, src_mcv),
6208 .bool_or,
6209 .bit_or,
6210 => try self.genBinOpMir(.{ ._, .@"or" }, lhs_ty, dst_mcv, src_mcv),
56696211
5670 .bool_and,
5671 .bit_and,
5672 => try self.genBinOpMir(.@"and", lhs_ty, dst_mcv, src_mcv),
6212 .bool_and,
6213 .bit_and,
6214 => try self.genBinOpMir(.{ ._, .@"and" }, lhs_ty, dst_mcv, src_mcv),
56736215
5674 .xor => try self.genBinOpMir(.xor, lhs_ty, dst_mcv, src_mcv),
6216 .xor => try self.genBinOpMir(.{ ._, .xor }, lhs_ty, dst_mcv, src_mcv),
56756217
5676 .min,
5677 .max,
5678 => switch (lhs_ty.zigTypeTag()) {
5679 .Int => {
6218 .min,
6219 .max,
6220 => {
56806221 const mat_src_mcv: MCValue = if (switch (src_mcv) {
56816222 .immediate,
56826223 .eflags,
......@@ -5698,16 +6239,16 @@ fn genBinOp(
56986239 };
56996240 defer if (mat_mcv_lock) |lock| self.register_manager.unlockReg(lock);
57006241
5701 try self.genBinOpMir(.cmp, lhs_ty, dst_mcv, mat_src_mcv);
6242 try self.genBinOpMir(.{ ._, .cmp }, lhs_ty, dst_mcv, mat_src_mcv);
57026243
57036244 const int_info = lhs_ty.intInfo(self.target.*);
57046245 const cc: Condition = switch (int_info.signedness) {
5705 .unsigned => switch (tag) {
6246 .unsigned => switch (air_tag) {
57066247 .min => .a,
57076248 .max => .b,
57086249 else => unreachable,
57096250 },
5710 .signed => switch (tag) {
6251 .signed => switch (air_tag) {
57116252 .min => .g,
57126253 .max => .l,
57136254 else => unreachable,
......@@ -5766,32 +6307,404 @@ fn genBinOp(
57666307 }
57676308 try self.genCopy(lhs_ty, dst_mcv, .{ .register = tmp_reg });
57686309 },
5769 .Float => try self.genBinOpMir(switch (lhs_ty.floatBits(self.target.*)) {
5770 32 => switch (tag) {
5771 .min => .minss,
5772 .max => .maxss,
5773 else => unreachable,
5774 },
5775 64 => switch (tag) {
5776 .min => .minsd,
5777 .max => .maxsd,
5778 else => unreachable,
5779 },
5780 else => return self.fail("TODO implement genBinOp for {s} {}", .{
5781 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5782 }),
5783 }, lhs_ty, dst_mcv, src_mcv),
6310
57846311 else => return self.fail("TODO implement genBinOp for {s} {}", .{
5785 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
6312 @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?),
57866313 }),
5787 },
6314 }
6315 return dst_mcv;
6316 }
57886317
6318 const dst_reg = registerAlias(dst_mcv.getReg().?, abi_size);
6319 const mir_tag = if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag()) {
6320 else => unreachable,
6321 .Float => switch (lhs_ty.floatBits(self.target.*)) {
6322 16 => if (self.hasFeature(.f16c)) {
6323 const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();
6324 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
6325 defer self.register_manager.unlockReg(tmp_lock);
6326
6327 if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(
6328 .{ .vp_w, .insr },
6329 dst_reg,
6330 dst_reg,
6331 src_mcv.mem(.word),
6332 Immediate.u(1),
6333 ) else try self.asmRegisterRegisterRegister(
6334 .{ .vp_, .unpcklwd },
6335 dst_reg,
6336 dst_reg,
6337 (if (src_mcv.isRegister())
6338 src_mcv.getReg().?
6339 else
6340 try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
6341 );
6342 try self.asmRegisterRegister(.{ .v_, .cvtph2ps }, dst_reg, dst_reg);
6343 try self.asmRegisterRegister(.{ .v_, .movshdup }, tmp_reg, dst_reg);
6344 try self.asmRegisterRegisterRegister(
6345 switch (air_tag) {
6346 .add => .{ .v_ss, .add },
6347 .sub => .{ .v_ss, .sub },
6348 .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_ss, .div },
6349 .max => .{ .v_ss, .max },
6350 .min => .{ .v_ss, .max },
6351 else => unreachable,
6352 },
6353 dst_reg,
6354 dst_reg,
6355 tmp_reg,
6356 );
6357 try self.asmRegisterRegisterImmediate(
6358 .{ .v_, .cvtps2ph },
6359 dst_reg,
6360 dst_reg,
6361 Immediate.u(0b1_00),
6362 );
6363 return dst_mcv;
6364 } else null,
6365 32 => switch (air_tag) {
6366 .add => if (self.hasFeature(.avx)) .{ .v_ss, .add } else .{ ._ss, .add },
6367 .sub => if (self.hasFeature(.avx)) .{ .v_ss, .sub } else .{ ._ss, .sub },
6368 .mul => if (self.hasFeature(.avx)) .{ .v_ss, .mul } else .{ ._ss, .mul },
6369 .div_float,
6370 .div_trunc,
6371 .div_floor,
6372 .div_exact,
6373 => if (self.hasFeature(.avx)) .{ .v_ss, .div } else .{ ._ss, .div },
6374 .max => if (self.hasFeature(.avx)) .{ .v_ss, .max } else .{ ._ss, .max },
6375 .min => if (self.hasFeature(.avx)) .{ .v_ss, .min } else .{ ._ss, .min },
6376 else => unreachable,
6377 },
6378 64 => switch (air_tag) {
6379 .add => if (self.hasFeature(.avx)) .{ .v_sd, .add } else .{ ._sd, .add },
6380 .sub => if (self.hasFeature(.avx)) .{ .v_sd, .sub } else .{ ._sd, .sub },
6381 .mul => if (self.hasFeature(.avx)) .{ .v_sd, .mul } else .{ ._sd, .mul },
6382 .div_float,
6383 .div_trunc,
6384 .div_floor,
6385 .div_exact,
6386 => if (self.hasFeature(.avx)) .{ .v_sd, .div } else .{ ._sd, .div },
6387 .max => if (self.hasFeature(.avx)) .{ .v_sd, .max } else .{ ._sd, .max },
6388 .min => if (self.hasFeature(.avx)) .{ .v_sd, .min } else .{ ._sd, .min },
6389 else => unreachable,
6390 },
6391 80, 128 => null,
6392 else => unreachable,
6393 },
6394 .Vector => switch (lhs_ty.childType().zigTypeTag()) {
6395 else => null,
6396 .Float => switch (lhs_ty.childType().floatBits(self.target.*)) {
6397 16 => if (self.hasFeature(.f16c)) switch (lhs_ty.vectorLen()) {
6398 1 => {
6399 const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();
6400 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
6401 defer self.register_manager.unlockReg(tmp_lock);
6402
6403 if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(
6404 .{ .vp_w, .insr },
6405 dst_reg,
6406 dst_reg,
6407 src_mcv.mem(.word),
6408 Immediate.u(1),
6409 ) else try self.asmRegisterRegisterRegister(
6410 .{ .vp_, .unpcklwd },
6411 dst_reg,
6412 dst_reg,
6413 (if (src_mcv.isRegister())
6414 src_mcv.getReg().?
6415 else
6416 try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
6417 );
6418 try self.asmRegisterRegister(.{ .v_, .cvtph2ps }, dst_reg, dst_reg);
6419 try self.asmRegisterRegister(.{ .v_, .movshdup }, tmp_reg, dst_reg);
6420 try self.asmRegisterRegisterRegister(
6421 switch (air_tag) {
6422 .add => .{ .v_ss, .add },
6423 .sub => .{ .v_ss, .sub },
6424 .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_ss, .div },
6425 .max => .{ .v_ss, .max },
6426 .min => .{ .v_ss, .max },
6427 else => unreachable,
6428 },
6429 dst_reg,
6430 dst_reg,
6431 tmp_reg,
6432 );
6433 try self.asmRegisterRegisterImmediate(
6434 .{ .v_, .cvtps2ph },
6435 dst_reg,
6436 dst_reg,
6437 Immediate.u(0b1_00),
6438 );
6439 return dst_mcv;
6440 },
6441 2 => {
6442 const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();
6443 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
6444 defer self.register_manager.unlockReg(tmp_lock);
6445
6446 if (src_mcv.isMemory()) try self.asmRegisterMemoryImmediate(
6447 .{ .vp_d, .insr },
6448 dst_reg,
6449 src_mcv.mem(.dword),
6450 Immediate.u(1),
6451 ) else try self.asmRegisterRegisterRegister(
6452 .{ .v_ps, .unpckl },
6453 dst_reg,
6454 dst_reg,
6455 (if (src_mcv.isRegister())
6456 src_mcv.getReg().?
6457 else
6458 try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
6459 );
6460 try self.asmRegisterRegister(.{ .v_, .cvtph2ps }, dst_reg, dst_reg);
6461 try self.asmRegisterRegisterRegister(
6462 .{ .v_ps, .movhl },
6463 tmp_reg,
6464 dst_reg,
6465 dst_reg,
6466 );
6467 try self.asmRegisterRegisterRegister(
6468 switch (air_tag) {
6469 .add => .{ .v_ps, .add },
6470 .sub => .{ .v_ps, .sub },
6471 .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_ps, .div },
6472 .max => .{ .v_ps, .max },
6473 .min => .{ .v_ps, .max },
6474 else => unreachable,
6475 },
6476 dst_reg,
6477 dst_reg,
6478 tmp_reg,
6479 );
6480 try self.asmRegisterRegisterImmediate(
6481 .{ .v_, .cvtps2ph },
6482 dst_reg,
6483 dst_reg,
6484 Immediate.u(0b1_00),
6485 );
6486 return dst_mcv;
6487 },
6488 3...4 => {
6489 const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();
6490 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
6491 defer self.register_manager.unlockReg(tmp_lock);
6492
6493 try self.asmRegisterRegister(.{ .v_, .cvtph2ps }, dst_reg, dst_reg);
6494 if (src_mcv.isMemory()) try self.asmRegisterMemory(
6495 .{ .v_, .cvtph2ps },
6496 tmp_reg,
6497 src_mcv.mem(.qword),
6498 ) else try self.asmRegisterRegister(
6499 .{ .v_, .cvtph2ps },
6500 tmp_reg,
6501 (if (src_mcv.isRegister())
6502 src_mcv.getReg().?
6503 else
6504 try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
6505 );
6506 try self.asmRegisterRegisterRegister(
6507 switch (air_tag) {
6508 .add => .{ .v_ps, .add },
6509 .sub => .{ .v_ps, .sub },
6510 .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_ps, .div },
6511 .max => .{ .v_ps, .max },
6512 .min => .{ .v_ps, .max },
6513 else => unreachable,
6514 },
6515 dst_reg,
6516 dst_reg,
6517 tmp_reg,
6518 );
6519 try self.asmRegisterRegisterImmediate(
6520 .{ .v_, .cvtps2ph },
6521 dst_reg,
6522 dst_reg,
6523 Immediate.u(0b1_00),
6524 );
6525 return dst_mcv;
6526 },
6527 5...8 => {
6528 const tmp_reg = (try self.register_manager.allocReg(null, sse)).to256();
6529 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
6530 defer self.register_manager.unlockReg(tmp_lock);
6531
6532 try self.asmRegisterRegister(.{ .v_, .cvtph2ps }, dst_reg.to256(), dst_reg);
6533 if (src_mcv.isMemory()) try self.asmRegisterMemory(
6534 .{ .v_, .cvtph2ps },
6535 tmp_reg,
6536 src_mcv.mem(.xword),
6537 ) else try self.asmRegisterRegister(
6538 .{ .v_, .cvtph2ps },
6539 tmp_reg,
6540 (if (src_mcv.isRegister())
6541 src_mcv.getReg().?
6542 else
6543 try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
6544 );
6545 try self.asmRegisterRegisterRegister(
6546 switch (air_tag) {
6547 .add => .{ .v_ps, .add },
6548 .sub => .{ .v_ps, .sub },
6549 .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_ps, .div },
6550 .max => .{ .v_ps, .max },
6551 .min => .{ .v_ps, .max },
6552 else => unreachable,
6553 },
6554 dst_reg.to256(),
6555 dst_reg.to256(),
6556 tmp_reg,
6557 );
6558 try self.asmRegisterRegisterImmediate(
6559 .{ .v_, .cvtps2ph },
6560 dst_reg,
6561 dst_reg.to256(),
6562 Immediate.u(0b1_00),
6563 );
6564 return dst_mcv;
6565 },
6566 else => null,
6567 } else null,
6568 32 => switch (lhs_ty.vectorLen()) {
6569 1 => switch (air_tag) {
6570 .add => if (self.hasFeature(.avx)) .{ .v_ss, .add } else .{ ._ss, .add },
6571 .sub => if (self.hasFeature(.avx)) .{ .v_ss, .sub } else .{ ._ss, .sub },
6572 .mul => if (self.hasFeature(.avx)) .{ .v_ss, .mul } else .{ ._ss, .mul },
6573 .div_float,
6574 .div_trunc,
6575 .div_floor,
6576 .div_exact,
6577 => if (self.hasFeature(.avx)) .{ .v_ss, .div } else .{ ._ss, .div },
6578 .max => if (self.hasFeature(.avx)) .{ .v_ss, .max } else .{ ._ss, .max },
6579 .min => if (self.hasFeature(.avx)) .{ .v_ss, .min } else .{ ._ss, .min },
6580 else => unreachable,
6581 },
6582 2...4 => switch (air_tag) {
6583 .add => if (self.hasFeature(.avx)) .{ .v_ps, .add } else .{ ._ps, .add },
6584 .sub => if (self.hasFeature(.avx)) .{ .v_ps, .sub } else .{ ._ps, .sub },
6585 .mul => if (self.hasFeature(.avx)) .{ .v_ps, .mul } else .{ ._ps, .mul },
6586 .div_float,
6587 .div_trunc,
6588 .div_floor,
6589 .div_exact,
6590 => if (self.hasFeature(.avx)) .{ .v_ps, .div } else .{ ._ps, .div },
6591 .max => if (self.hasFeature(.avx)) .{ .v_ps, .max } else .{ ._ps, .max },
6592 .min => if (self.hasFeature(.avx)) .{ .v_ps, .min } else .{ ._ps, .min },
6593 else => unreachable,
6594 },
6595 5...8 => if (self.hasFeature(.avx)) switch (air_tag) {
6596 .add => .{ .v_ps, .add },
6597 .sub => .{ .v_ps, .sub },
6598 .mul => .{ .v_ps, .mul },
6599 .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_ps, .div },
6600 .max => .{ .v_ps, .max },
6601 .min => .{ .v_ps, .min },
6602 else => unreachable,
6603 } else null,
6604 else => null,
6605 },
6606 64 => switch (lhs_ty.vectorLen()) {
6607 1 => switch (air_tag) {
6608 .add => if (self.hasFeature(.avx)) .{ .v_sd, .add } else .{ ._sd, .add },
6609 .sub => if (self.hasFeature(.avx)) .{ .v_sd, .sub } else .{ ._sd, .sub },
6610 .mul => if (self.hasFeature(.avx)) .{ .v_sd, .mul } else .{ ._sd, .mul },
6611 .div_float,
6612 .div_trunc,
6613 .div_floor,
6614 .div_exact,
6615 => if (self.hasFeature(.avx)) .{ .v_sd, .div } else .{ ._sd, .div },
6616 .max => if (self.hasFeature(.avx)) .{ .v_sd, .max } else .{ ._sd, .max },
6617 .min => if (self.hasFeature(.avx)) .{ .v_sd, .min } else .{ ._sd, .min },
6618 else => unreachable,
6619 },
6620 2 => switch (air_tag) {
6621 .add => if (self.hasFeature(.avx)) .{ .v_pd, .add } else .{ ._pd, .add },
6622 .sub => if (self.hasFeature(.avx)) .{ .v_pd, .sub } else .{ ._pd, .sub },
6623 .mul => if (self.hasFeature(.avx)) .{ .v_pd, .mul } else .{ ._pd, .mul },
6624 .div_float,
6625 .div_trunc,
6626 .div_floor,
6627 .div_exact,
6628 => if (self.hasFeature(.avx)) .{ .v_pd, .div } else .{ ._pd, .div },
6629 .max => if (self.hasFeature(.avx)) .{ .v_pd, .max } else .{ ._pd, .max },
6630 .min => if (self.hasFeature(.avx)) .{ .v_pd, .min } else .{ ._pd, .min },
6631 else => unreachable,
6632 },
6633 3...4 => if (self.hasFeature(.avx)) switch (air_tag) {
6634 .add => .{ .v_pd, .add },
6635 .sub => .{ .v_pd, .sub },
6636 .mul => .{ .v_pd, .mul },
6637 .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_pd, .div },
6638 .max => .{ .v_pd, .max },
6639 .min => .{ .v_pd, .min },
6640 else => unreachable,
6641 } else null,
6642 else => null,
6643 },
6644 80, 128 => null,
6645 else => unreachable,
6646 },
6647 },
6648 })) |tag| tag else return self.fail("TODO implement genBinOp for {s} {}", .{
6649 @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?),
6650 });
6651 if (self.hasFeature(.avx)) {
6652 const src1_alias =
6653 if (copied_to_dst) dst_reg else registerAlias(lhs_mcv.getReg().?, abi_size);
6654 if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
6655 mir_tag,
6656 dst_reg,
6657 src1_alias,
6658 src_mcv.mem(Memory.PtrSize.fromSize(abi_size)),
6659 ) else try self.asmRegisterRegisterRegister(
6660 mir_tag,
6661 dst_reg,
6662 src1_alias,
6663 registerAlias(if (src_mcv.isRegister())
6664 src_mcv.getReg().?
6665 else
6666 try self.copyToTmpRegister(rhs_ty, src_mcv), abi_size),
6667 );
6668 } else {
6669 assert(copied_to_dst);
6670 if (src_mcv.isMemory()) try self.asmRegisterMemory(
6671 mir_tag,
6672 dst_reg,
6673 src_mcv.mem(Memory.PtrSize.fromSize(abi_size)),
6674 ) else try self.asmRegisterRegister(
6675 mir_tag,
6676 dst_reg,
6677 registerAlias(if (src_mcv.isRegister())
6678 src_mcv.getReg().?
6679 else
6680 try self.copyToTmpRegister(rhs_ty, src_mcv), abi_size),
6681 );
6682 }
6683 switch (air_tag) {
6684 .add, .sub, .mul, .div_float, .div_exact => {},
6685 .div_trunc, .div_floor => try self.genRound(
6686 lhs_ty,
6687 dst_reg,
6688 .{ .register = dst_reg },
6689 switch (air_tag) {
6690 .div_trunc => 0b1_0_11,
6691 .div_floor => 0b1_0_01,
6692 else => unreachable,
6693 },
6694 ),
6695 .max, .min => {}, // TODO: unordered select
57896696 else => unreachable,
57906697 }
57916698 return dst_mcv;
57926699}
57936700
5794fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
6701fn genBinOpMir(
6702 self: *Self,
6703 mir_tag: Mir.Inst.FixedTag,
6704 ty: Type,
6705 dst_mcv: MCValue,
6706 src_mcv: MCValue,
6707) !void {
57956708 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
57966709 switch (dst_mcv) {
57976710 .none,
......@@ -5818,20 +6731,11 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
58186731 .register_overflow,
58196732 .reserved_frame,
58206733 => unreachable,
5821 .register => |src_reg| switch (ty.zigTypeTag()) {
5822 .Float => {
5823 if (!Target.x86.featureSetHas(self.target.cpu.features, .sse))
5824 return self.fail("TODO genBinOpMir for {s} {} without sse", .{
5825 @tagName(mir_tag), ty.fmt(self.bin_file.options.module.?),
5826 });
5827 return self.asmRegisterRegister(mir_tag, dst_reg.to128(), src_reg.to128());
5828 },
5829 else => try self.asmRegisterRegister(
5830 mir_tag,
5831 dst_alias,
5832 registerAlias(src_reg, abi_size),
5833 ),
5834 },
6734 .register => |src_reg| try self.asmRegisterRegister(
6735 mir_tag,
6736 dst_alias,
6737 registerAlias(src_reg, abi_size),
6738 ),
58356739 .immediate => |imm| switch (self.regBitSize(ty)) {
58366740 8 => try self.asmRegisterImmediate(
58376741 mir_tag,
......@@ -6005,14 +6909,14 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
60056909 };
60066910 var off: i32 = 0;
60076911 while (off < abi_size) : (off += 8) {
6008 const mir_limb_tag = switch (off) {
6912 const mir_limb_tag: Mir.Inst.FixedTag = switch (off) {
60096913 0 => mir_tag,
6010 else => switch (mir_tag) {
6011 .add => .adc,
6012 .sub, .cmp => .sbb,
6914 else => switch (mir_tag[1]) {
6915 .add => .{ ._, .adc },
6916 .sub, .cmp => .{ ._, .sbb },
60136917 .@"or", .@"and", .xor => mir_tag,
60146918 else => return self.fail("TODO genBinOpMir implement large ABI for {s}", .{
6015 @tagName(mir_tag),
6919 @tagName(mir_tag[1]),
60166920 }),
60176921 },
60186922 };
......@@ -6184,14 +7088,14 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
61847088 .reserved_frame,
61857089 => unreachable,
61867090 .register => |src_reg| try self.asmRegisterRegister(
6187 .imul,
7091 .{ .i_, .mul },
61887092 dst_alias,
61897093 registerAlias(src_reg, abi_size),
61907094 ),
61917095 .immediate => |imm| {
61927096 if (math.cast(i32, imm)) |small| {
61937097 try self.asmRegisterRegisterImmediate(
6194 .imul,
7098 .{ .i_, .mul },
61957099 dst_alias,
61967100 dst_alias,
61977101 Immediate.s(small),
......@@ -6211,19 +7115,19 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
62117115 .lea_tlv,
62127116 .lea_frame,
62137117 => try self.asmRegisterRegister(
6214 .imul,
7118 .{ .i_, .mul },
62157119 dst_alias,
62167120 registerAlias(try self.copyToTmpRegister(dst_ty, src_mcv), abi_size),
62177121 ),
62187122 .memory, .indirect, .load_frame => try self.asmRegisterMemory(
6219 .imul,
7123 .{ .i_, .mul },
62207124 dst_alias,
62217125 Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (src_mcv) {
62227126 .memory => |addr| .{
62237127 .base = .{ .reg = .ds },
62247128 .disp = math.cast(i32, @bitCast(i64, addr)) orelse
62257129 return self.asmRegisterRegister(
6226 .imul,
7130 .{ .i_, .mul },
62277131 dst_alias,
62287132 registerAlias(try self.copyToTmpRegister(dst_ty, src_mcv), abi_size),
62297133 ),
......@@ -6348,12 +7252,12 @@ fn genVarDbgInfo(
63487252}
63497253
63507254fn airTrap(self: *Self) !void {
6351 try self.asmOpOnly(.ud2);
7255 try self.asmOpOnly(.{ ._, .ud2 });
63527256 return self.finishAirBookkeeping();
63537257}
63547258
63557259fn airBreakpoint(self: *Self) !void {
6356 try self.asmOpOnly(.int3);
7260 try self.asmOpOnly(.{ ._, .int3 });
63577261 return self.finishAirBookkeeping();
63587262}
63597263
......@@ -6374,7 +7278,7 @@ fn airFence(self: *Self, inst: Air.Inst.Index) !void {
63747278 switch (order) {
63757279 .Unordered, .Monotonic => unreachable,
63767280 .Acquire, .Release, .AcqRel => {},
6377 .SeqCst => try self.asmOpOnly(.mfence),
7281 .SeqCst => try self.asmOpOnly(.{ ._, .mfence }),
63787282 }
63797283 return self.finishAirBookkeeping();
63807284}
......@@ -6468,7 +7372,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
64687372 const atom = elf_file.getAtom(atom_index);
64697373 _ = try atom.getOrCreateOffsetTableEntry(elf_file);
64707374 const got_addr = atom.getOffsetTableAddress(elf_file);
6471 try self.asmMemory(.call, Memory.sib(.qword, .{
7375 try self.asmMemory(.{ ._, .call }, Memory.sib(.qword, .{
64727376 .base = .{ .reg = .ds },
64737377 .disp = @intCast(i32, got_addr),
64747378 }));
......@@ -6476,12 +7380,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
64767380 const atom = try coff_file.getOrCreateAtomForDecl(func.owner_decl);
64777381 const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;
64787382 try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });
6479 try self.asmRegister(.call, .rax);
7383 try self.asmRegister(.{ ._, .call }, .rax);
64807384 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
64817385 const atom = try macho_file.getOrCreateAtomForDecl(func.owner_decl);
64827386 const sym_index = macho_file.getAtom(atom).getSymbolIndex().?;
64837387 try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });
6484 try self.asmRegister(.call, .rax);
7388 try self.asmRegister(.{ ._, .call }, .rax);
64857389 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
64867390 const decl_block_index = try p9.seeDecl(func.owner_decl);
64877391 const decl_block = p9.getDeclBlock(decl_block_index);
......@@ -6490,7 +7394,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
64907394 const got_addr = p9.bases.data;
64917395 const got_index = decl_block.got_index.?;
64927396 const fn_got_addr = got_addr + got_index * ptr_bytes;
6493 try self.asmMemory(.call, Memory.sib(.qword, .{
7397 try self.asmMemory(.{ ._, .call }, Memory.sib(.qword, .{
64947398 .base = .{ .reg = .ds },
64957399 .disp = @intCast(i32, fn_got_addr),
64967400 }));
......@@ -6503,22 +7407,24 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
65037407 const atom_index = try self.owner.getSymbolIndex(self);
65047408 const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name);
65057409 _ = try self.addInst(.{
6506 .tag = .mov_linker,
7410 .tag = .mov,
65077411 .ops = .import_reloc,
6508 .data = .{ .payload = try self.addExtra(Mir.LeaRegisterReloc{
6509 .reg = @enumToInt(Register.rax),
6510 .atom_index = atom_index,
6511 .sym_index = sym_index,
6512 }) },
7412 .data = .{ .rx = .{
7413 .r1 = .rax,
7414 .payload = try self.addExtra(Mir.Reloc{
7415 .atom_index = atom_index,
7416 .sym_index = sym_index,
7417 }),
7418 } },
65137419 });
6514 try self.asmRegister(.call, .rax);
7420 try self.asmRegister(.{ ._, .call }, .rax);
65157421 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
65167422 const atom_index = try self.owner.getSymbolIndex(self);
65177423 const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name);
65187424 _ = try self.addInst(.{
6519 .tag = .call_extern,
6520 .ops = undefined,
6521 .data = .{ .relocation = .{
7425 .tag = .call,
7426 .ops = .extern_fn_reloc,
7427 .data = .{ .reloc = .{
65227428 .atom_index = atom_index,
65237429 .sym_index = sym_index,
65247430 } },
......@@ -6533,7 +7439,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
65337439 assert(ty.zigTypeTag() == .Pointer);
65347440 const mcv = try self.resolveInst(callee);
65357441 try self.genSetReg(.rax, Type.usize, mcv);
6536 try self.asmRegister(.call, .rax);
7442 try self.asmRegister(.{ ._, .call }, .rax);
65377443 }
65387444
65397445 var bt = self.liveness.iterateBigTomb(inst);
......@@ -6588,8 +7494,6 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
65887494fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
65897495 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
65907496 const ty = self.air.typeOf(bin_op.lhs);
6591 const ty_abi_size = ty.abiSize(self.target.*);
6592 const can_reuse = ty_abi_size <= 8;
65937497
65947498 try self.spillEflagsIfOccupied();
65957499 self.eflags_inst = inst;
......@@ -6608,52 +7512,103 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
66087512 };
66097513 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
66107514
6611 const dst_mem_ok = !ty.isRuntimeFloat();
6612 var flipped = false;
6613 const dst_mcv: MCValue = if (can_reuse and !lhs_mcv.isImmediate() and
6614 (dst_mem_ok or lhs_mcv.isRegister()) and self.liveness.operandDies(inst, 0))
6615 lhs_mcv
6616 else if (can_reuse and !rhs_mcv.isImmediate() and
6617 (dst_mem_ok or rhs_mcv.isRegister()) and self.liveness.operandDies(inst, 1))
6618 dst: {
6619 flipped = true;
6620 break :dst rhs_mcv;
6621 } else if (dst_mem_ok) dst: {
6622 const dst_mcv = try self.allocTempRegOrMem(ty, true);
6623 try self.genCopy(ty, dst_mcv, lhs_mcv);
6624 break :dst dst_mcv;
6625 } else .{ .register = try self.copyToTmpRegister(ty, lhs_mcv) };
6626 const dst_lock = switch (dst_mcv) {
6627 .register => |reg| self.register_manager.lockReg(reg),
6628 else => null,
6629 };
6630 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
7515 const result = MCValue{
7516 .eflags = switch (ty.zigTypeTag()) {
7517 else => result: {
7518 var flipped = false;
7519 const dst_mcv: MCValue = if (lhs_mcv.isRegister() or lhs_mcv.isMemory())
7520 lhs_mcv
7521 else if (rhs_mcv.isRegister() or rhs_mcv.isMemory()) dst: {
7522 flipped = true;
7523 break :dst rhs_mcv;
7524 } else .{ .register = try self.copyToTmpRegister(ty, lhs_mcv) };
7525 const dst_lock = switch (dst_mcv) {
7526 .register => |reg| self.register_manager.lockReg(reg),
7527 else => null,
7528 };
7529 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
7530 const src_mcv = if (flipped) lhs_mcv else rhs_mcv;
66317531
6632 const src_mcv = if (flipped) lhs_mcv else rhs_mcv;
6633 try self.genBinOpMir(switch (ty.zigTypeTag()) {
6634 else => .cmp,
6635 .Float => switch (ty.floatBits(self.target.*)) {
6636 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse))
6637 .ucomiss
6638 else
6639 return self.fail("TODO implement airCmp for {} without sse", .{
6640 ty.fmt(self.bin_file.options.module.?),
6641 }),
6642 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2))
6643 .ucomisd
6644 else
6645 return self.fail("TODO implement airCmp for {} without sse2", .{
6646 ty.fmt(self.bin_file.options.module.?),
6647 }),
6648 else => return self.fail("TODO implement airCmp for {}", .{
6649 ty.fmt(self.bin_file.options.module.?),
6650 }),
6651 },
6652 }, ty, dst_mcv, src_mcv);
7532 try self.genBinOpMir(.{ ._, .cmp }, ty, dst_mcv, src_mcv);
7533 break :result Condition.fromCompareOperator(
7534 if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned,
7535 if (flipped) op.reverse() else op,
7536 );
7537 },
7538 .Float => result: {
7539 const flipped = switch (op) {
7540 .lt, .lte => true,
7541 .eq, .gte, .gt, .neq => false,
7542 };
66537543
6654 const signedness = if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned;
6655 const result = MCValue{
6656 .eflags = Condition.fromCompareOperator(signedness, if (flipped) op.reverse() else op),
7544 const dst_mcv = if (flipped) rhs_mcv else lhs_mcv;
7545 const dst_reg = if (dst_mcv.isRegister())
7546 dst_mcv.getReg().?
7547 else
7548 try self.copyToTmpRegister(ty, dst_mcv);
7549 const dst_lock = self.register_manager.lockReg(dst_reg);
7550 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
7551 const src_mcv = if (flipped) lhs_mcv else rhs_mcv;
7552
7553 switch (ty.floatBits(self.target.*)) {
7554 16 => if (self.hasFeature(.f16c)) {
7555 const tmp1_reg = (try self.register_manager.allocReg(null, sse)).to128();
7556 const tmp1_mcv = MCValue{ .register = tmp1_reg };
7557 const tmp1_lock = self.register_manager.lockRegAssumeUnused(tmp1_reg);
7558 defer self.register_manager.unlockReg(tmp1_lock);
7559
7560 const tmp2_reg = (try self.register_manager.allocReg(null, sse)).to128();
7561 const tmp2_mcv = MCValue{ .register = tmp2_reg };
7562 const tmp2_lock = self.register_manager.lockRegAssumeUnused(tmp2_reg);
7563 defer self.register_manager.unlockReg(tmp2_lock);
7564
7565 if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(
7566 .{ .vp_w, .insr },
7567 tmp1_reg,
7568 dst_reg.to128(),
7569 src_mcv.mem(.word),
7570 Immediate.u(1),
7571 ) else try self.asmRegisterRegisterRegister(
7572 .{ .vp_, .unpcklwd },
7573 tmp1_reg,
7574 dst_reg.to128(),
7575 (if (src_mcv.isRegister())
7576 src_mcv.getReg().?
7577 else
7578 try self.copyToTmpRegister(ty, src_mcv)).to128(),
7579 );
7580 try self.asmRegisterRegister(.{ .v_, .cvtph2ps }, tmp1_reg, tmp1_reg);
7581 try self.asmRegisterRegister(.{ .v_, .movshdup }, tmp2_reg, tmp1_reg);
7582 try self.genBinOpMir(.{ ._ss, .ucomi }, ty, tmp1_mcv, tmp2_mcv);
7583 } else return self.fail("TODO implement airCmp for {}", .{
7584 ty.fmt(self.bin_file.options.module.?),
7585 }),
7586 32 => try self.genBinOpMir(
7587 .{ ._ss, .ucomi },
7588 ty,
7589 .{ .register = dst_reg },
7590 src_mcv,
7591 ),
7592 64 => try self.genBinOpMir(
7593 .{ ._sd, .ucomi },
7594 ty,
7595 .{ .register = dst_reg },
7596 src_mcv,
7597 ),
7598 else => return self.fail("TODO implement airCmp for {}", .{
7599 ty.fmt(self.bin_file.options.module.?),
7600 }),
7601 }
7602
7603 break :result switch (if (flipped) op.reverse() else op) {
7604 .lt, .lte => unreachable, // required to have been canonicalized to gt(e)
7605 .gt => .a,
7606 .gte => .ae,
7607 .eq => .z_and_np,
7608 .neq => .nz_or_p,
7609 };
7610 },
7611 },
66577612 };
66587613 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
66597614}
......@@ -6683,7 +7638,7 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {
66837638 else => try self.copyToTmpRegister(op_ty, op_mcv),
66847639 };
66857640 try self.asmRegisterMemory(
6686 .cmp,
7641 .{ ._, .cmp },
66877642 registerAlias(dst_reg, op_abi_size),
66887643 Memory.sib(Memory.PtrSize.fromSize(op_abi_size), .{ .base = .{ .reg = addr_reg } }),
66897644 );
......@@ -6757,8 +7712,8 @@ fn genTry(
67577712fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
67587713 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
67597714 _ = try self.addInst(.{
6760 .tag = .dbg_line,
6761 .ops = undefined,
7715 .tag = .pseudo,
7716 .ops = .pseudo_dbg_line_line_column,
67627717 .data = .{ .line_column = .{
67637718 .line = dbg_stmt.line,
67647719 .column = dbg_stmt.column,
......@@ -6803,7 +7758,7 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {
68037758 },
68047759 .register => |reg| {
68057760 try self.spillEflagsIfOccupied();
6806 try self.asmRegisterImmediate(.@"test", reg, Immediate.u(1));
7761 try self.asmRegisterImmediate(.{ ._, .@"test" }, reg, Immediate.u(1));
68077762 return self.asmJccReloc(undefined, .e);
68087763 },
68097764 .immediate,
......@@ -6906,13 +7861,13 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
69067861 const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*));
69077862 const alias_reg = registerAlias(opt_reg, some_abi_size);
69087863 assert(some_abi_size * 8 == alias_reg.bitSize());
6909 try self.asmRegisterRegister(.@"test", alias_reg, alias_reg);
7864 try self.asmRegisterRegister(.{ ._, .@"test" }, alias_reg, alias_reg);
69107865 return .{ .eflags = .z };
69117866 }
69127867 assert(some_info.ty.tag() == .bool);
69137868 const opt_abi_size = @intCast(u32, opt_ty.abiSize(self.target.*));
69147869 try self.asmRegisterImmediate(
6915 .bt,
7870 .{ ._, .bt },
69167871 registerAlias(opt_reg, opt_abi_size),
69177872 Immediate.u(@intCast(u6, some_info.off * 8)),
69187873 );
......@@ -6931,7 +7886,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
69317886 try self.genSetReg(addr_reg, Type.usize, opt_mcv.address());
69327887 const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*));
69337888 try self.asmMemoryImmediate(
6934 .cmp,
7889 .{ ._, .cmp },
69357890 Memory.sib(Memory.PtrSize.fromSize(some_abi_size), .{
69367891 .base = .{ .reg = addr_reg },
69377892 .disp = some_info.off,
......@@ -6944,7 +7899,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
69447899 .indirect, .load_frame => {
69457900 const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*));
69467901 try self.asmMemoryImmediate(
6947 .cmp,
7902 .{ ._, .cmp },
69487903 Memory.sib(Memory.PtrSize.fromSize(some_abi_size), switch (opt_mcv) {
69497904 .indirect => |reg_off| .{
69507905 .base = .{ .reg = reg_off.reg },
......@@ -6986,7 +7941,7 @@ fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue)
69867941
69877942 const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*));
69887943 try self.asmMemoryImmediate(
6989 .cmp,
7944 .{ ._, .cmp },
69907945 Memory.sib(Memory.PtrSize.fromSize(some_abi_size), .{
69917946 .base = .{ .reg = ptr_reg },
69927947 .disp = some_info.off,
......@@ -7017,14 +7972,24 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) !
70177972 const tmp_reg = try self.copyToTmpRegister(ty, operand);
70187973 if (err_off > 0) {
70197974 const shift = @intCast(u6, err_off * 8);
7020 try self.genShiftBinOpMir(.shr, ty, .{ .register = tmp_reg }, .{ .immediate = shift });
7975 try self.genShiftBinOpMir(
7976 .{ ._r, .sh },
7977 ty,
7978 .{ .register = tmp_reg },
7979 .{ .immediate = shift },
7980 );
70217981 } else {
70227982 try self.truncateRegister(Type.anyerror, tmp_reg);
70237983 }
7024 try self.genBinOpMir(.cmp, Type.anyerror, .{ .register = tmp_reg }, .{ .immediate = 0 });
7984 try self.genBinOpMir(
7985 .{ ._, .cmp },
7986 Type.anyerror,
7987 .{ .register = tmp_reg },
7988 .{ .immediate = 0 },
7989 );
70257990 },
70267991 .load_frame => |frame_addr| try self.genBinOpMir(
7027 .cmp,
7992 .{ ._, .cmp },
70287993 Type.anyerror,
70297994 .{ .load_frame = .{
70307995 .index = frame_addr.index,
......@@ -7249,7 +8214,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
72498214 try self.spillEflagsIfOccupied();
72508215 for (items, relocs, 0..) |item, *reloc, i| {
72518216 const item_mcv = try self.resolveInst(item);
7252 try self.genBinOpMir(.cmp, condition_ty, condition, item_mcv);
8217 try self.genBinOpMir(.{ ._, .cmp }, condition_ty, condition, item_mcv);
72538218 reloc.* = try self.asmJccReloc(undefined, if (i < relocs.len - 1) .e else .ne);
72548219 }
72558220
......@@ -7289,14 +8254,14 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
72898254fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {
72908255 const next_inst = @intCast(u32, self.mir_instructions.len);
72918256 switch (self.mir_instructions.items(.tag)[reloc]) {
7292 .jcc => {
7293 self.mir_instructions.items(.data)[reloc].inst_cc.inst = next_inst;
7294 },
7295 .jmp_reloc => {
7296 self.mir_instructions.items(.data)[reloc].inst = next_inst;
8257 .j, .jmp => {},
8258 .pseudo => switch (self.mir_instructions.items(.ops)[reloc]) {
8259 .pseudo_j_z_and_np_inst, .pseudo_j_nz_or_p_inst => {},
8260 else => unreachable,
72978261 },
72988262 else => unreachable,
72998263 }
8264 self.mir_instructions.items(.data)[reloc].inst.inst = next_inst;
73008265}
73018266
73028267fn airBr(self: *Self, inst: Air.Inst.Index) !void {
......@@ -7460,7 +8425,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
74608425 .qword
74618426 else
74628427 null;
7463 const mnem = mnem: {
8428 const mnem_tag = Mir.Inst.FixedTag{ ._, mnem: {
74648429 if (mnem_size) |_| {
74658430 if (std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1])) |mnem| {
74668431 break :mnem mnem;
......@@ -7468,7 +8433,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
74688433 }
74698434 break :mnem std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse
74708435 return self.fail("Invalid mnemonic: '{s}'", .{mnem_str});
7471 };
8436 } };
74728437
74738438 var op_it = mem.tokenize(u8, mnem_it.rest(), ",");
74748439 var ops = [1]encoder.Instruction.Operand{.none} ** 4;
......@@ -7519,51 +8484,51 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
75198484 } else if (op_it.next()) |op_str| return self.fail("Extra operand: '{s}'", .{op_str});
75208485
75218486 (switch (ops[0]) {
7522 .none => self.asmOpOnly(mnem),
8487 .none => self.asmOpOnly(mnem_tag),
75238488 .reg => |reg0| switch (ops[1]) {
7524 .none => self.asmRegister(mnem, reg0),
8489 .none => self.asmRegister(mnem_tag, reg0),
75258490 .reg => |reg1| switch (ops[2]) {
7526 .none => self.asmRegisterRegister(mnem, reg1, reg0),
8491 .none => self.asmRegisterRegister(mnem_tag, reg1, reg0),
75278492 .reg => |reg2| switch (ops[3]) {
7528 .none => self.asmRegisterRegisterRegister(mnem, reg2, reg1, reg0),
8493 .none => self.asmRegisterRegisterRegister(mnem_tag, reg2, reg1, reg0),
75298494 else => error.InvalidInstruction,
75308495 },
75318496 .mem => |mem2| switch (ops[3]) {
7532 .none => self.asmMemoryRegisterRegister(mnem, mem2, reg1, reg0),
8497 .none => self.asmMemoryRegisterRegister(mnem_tag, mem2, reg1, reg0),
75338498 else => error.InvalidInstruction,
75348499 },
75358500 else => error.InvalidInstruction,
75368501 },
75378502 .mem => |mem1| switch (ops[2]) {
7538 .none => self.asmMemoryRegister(mnem, mem1, reg0),
8503 .none => self.asmMemoryRegister(mnem_tag, mem1, reg0),
75398504 else => error.InvalidInstruction,
75408505 },
75418506 else => error.InvalidInstruction,
75428507 },
75438508 .mem => |mem0| switch (ops[1]) {
7544 .none => self.asmMemory(mnem, mem0),
8509 .none => self.asmMemory(mnem_tag, mem0),
75458510 .reg => |reg1| switch (ops[2]) {
7546 .none => self.asmRegisterMemory(mnem, reg1, mem0),
8511 .none => self.asmRegisterMemory(mnem_tag, reg1, mem0),
75478512 else => error.InvalidInstruction,
75488513 },
75498514 else => error.InvalidInstruction,
75508515 },
75518516 .imm => |imm0| switch (ops[1]) {
7552 .none => self.asmImmediate(mnem, imm0),
8517 .none => self.asmImmediate(mnem_tag, imm0),
75538518 .reg => |reg1| switch (ops[2]) {
7554 .none => self.asmRegisterImmediate(mnem, reg1, imm0),
8519 .none => self.asmRegisterImmediate(mnem_tag, reg1, imm0),
75558520 .reg => |reg2| switch (ops[3]) {
7556 .none => self.asmRegisterRegisterImmediate(mnem, reg2, reg1, imm0),
8521 .none => self.asmRegisterRegisterImmediate(mnem_tag, reg2, reg1, imm0),
75578522 else => error.InvalidInstruction,
75588523 },
75598524 .mem => |mem2| switch (ops[3]) {
7560 .none => self.asmMemoryRegisterImmediate(mnem, mem2, reg1, imm0),
8525 .none => self.asmMemoryRegisterImmediate(mnem_tag, mem2, reg1, imm0),
75618526 else => error.InvalidInstruction,
75628527 },
75638528 else => error.InvalidInstruction,
75648529 },
75658530 .mem => |mem1| switch (ops[2]) {
7566 .none => self.asmMemoryImmediate(mnem, mem1, imm0),
8531 .none => self.asmMemoryImmediate(mnem_tag, mem1, imm0),
75678532 else => error.InvalidInstruction,
75688533 },
75698534 else => error.InvalidInstruction,
......@@ -7572,7 +8537,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
75728537 error.InvalidInstruction => return self.fail(
75738538 "Invalid instruction: '{s} {s} {s} {s} {s}'",
75748539 .{
7575 @tagName(mnem),
8540 @tagName(mnem_tag[1]),
75768541 @tagName(ops[0]),
75778542 @tagName(ops[1]),
75788543 @tagName(ops[2]),
......@@ -7603,19 +8568,55 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
76038568 return self.finishAirResult(inst, result);
76048569}
76058570
7606fn movMirTag(self: *Self, ty: Type) !Mir.Inst.Tag {
7607 return switch (ty.zigTypeTag()) {
7608 else => .mov,
8571fn movMirTag(self: *Self, ty: Type, aligned: bool) !Mir.Inst.FixedTag {
8572 switch (ty.zigTypeTag()) {
8573 else => return .{ ._, .mov },
76098574 .Float => switch (ty.floatBits(self.target.*)) {
76108575 16 => unreachable, // needs special handling
7611 32 => .movss,
7612 64 => .movsd,
7613 128 => .movaps,
7614 else => return self.fail("TODO movMirTag from {}", .{
7615 ty.fmt(self.bin_file.options.module.?),
7616 }),
8576 32 => return if (self.hasFeature(.avx)) .{ .v_ss, .mov } else .{ ._ss, .mov },
8577 64 => return if (self.hasFeature(.avx)) .{ .v_sd, .mov } else .{ ._sd, .mov },
8578 128 => return if (self.hasFeature(.avx))
8579 if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu }
8580 else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu },
8581 else => {},
76178582 },
7618 };
8583 .Vector => switch (ty.childType().zigTypeTag()) {
8584 .Float => switch (ty.childType().floatBits(self.target.*)) {
8585 16 => switch (ty.vectorLen()) {
8586 1 => unreachable, // needs special handling
8587 2 => return if (self.hasFeature(.avx)) .{ .v_ss, .mov } else .{ ._ss, .mov },
8588 3...4 => return if (self.hasFeature(.avx)) .{ .v_sd, .mov } else .{ ._sd, .mov },
8589 5...8 => return if (self.hasFeature(.avx))
8590 if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu }
8591 else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu },
8592 9...16 => if (self.hasFeature(.avx))
8593 return if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu },
8594 else => {},
8595 },
8596 32 => switch (ty.vectorLen()) {
8597 1 => return if (self.hasFeature(.avx)) .{ .v_ss, .mov } else .{ ._ss, .mov },
8598 2...4 => return if (self.hasFeature(.avx))
8599 if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu }
8600 else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu },
8601 5...8 => if (self.hasFeature(.avx))
8602 return if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu },
8603 else => {},
8604 },
8605 64 => switch (ty.vectorLen()) {
8606 1 => return if (self.hasFeature(.avx)) .{ .v_sd, .mov } else .{ ._sd, .mov },
8607 2 => return if (self.hasFeature(.avx))
8608 if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu }
8609 else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu },
8610 3...4 => if (self.hasFeature(.avx))
8611 return if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu },
8612 else => {},
8613 },
8614 else => {},
8615 },
8616 else => {},
8617 },
8618 }
8619 return self.fail("TODO movMirTag for {}", .{ty.fmt(self.bin_file.options.module.?)});
76198620}
76208621
76218622fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void {
......@@ -7685,7 +8686,8 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError
76858686
76868687fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerError!void {
76878688 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
7688 if (abi_size > 8) return self.fail("genSetReg called with a value larger than one register", .{});
8689 if (abi_size * 8 > dst_reg.bitSize())
8690 return self.fail("genSetReg called with a value larger than dst_reg", .{});
76898691 switch (src_mcv) {
76908692 .none,
76918693 .unreach,
......@@ -7700,19 +8702,19 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
77008702 if (imm == 0) {
77018703 // 32-bit moves zero-extend to 64-bit, so xoring the 32-bit
77028704 // register is the fastest way to zero a register.
7703 try self.asmRegisterRegister(.xor, dst_reg.to32(), dst_reg.to32());
8705 try self.asmRegisterRegister(.{ ._, .xor }, dst_reg.to32(), dst_reg.to32());
77048706 } else if (abi_size > 4 and math.cast(u32, imm) != null) {
77058707 // 32-bit moves zero-extend to 64-bit.
7706 try self.asmRegisterImmediate(.mov, dst_reg.to32(), Immediate.u(imm));
8708 try self.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to32(), Immediate.u(imm));
77078709 } else if (abi_size <= 4 and @bitCast(i64, imm) < 0) {
77088710 try self.asmRegisterImmediate(
7709 .mov,
8711 .{ ._, .mov },
77108712 registerAlias(dst_reg, abi_size),
77118713 Immediate.s(@intCast(i32, @bitCast(i64, imm))),
77128714 );
77138715 } else {
77148716 try self.asmRegisterImmediate(
7715 .mov,
8717 .{ ._, .mov },
77168718 registerAlias(dst_reg, abi_size),
77178719 Immediate.u(imm),
77188720 );
......@@ -7721,18 +8723,18 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
77218723 .register => |src_reg| if (dst_reg.id() != src_reg.id()) try self.asmRegisterRegister(
77228724 if ((dst_reg.class() == .floating_point) == (src_reg.class() == .floating_point))
77238725 switch (ty.zigTypeTag()) {
7724 else => .mov,
7725 .Float, .Vector => .movaps,
8726 else => .{ ._, .mov },
8727 .Float, .Vector => .{ ._ps, .mova },
77268728 }
77278729 else switch (abi_size) {
77288730 2 => return try self.asmRegisterRegisterImmediate(
7729 if (dst_reg.class() == .floating_point) .pinsrw else .pextrw,
7730 registerAlias(dst_reg, abi_size),
7731 registerAlias(src_reg, abi_size),
8731 if (dst_reg.class() == .floating_point) .{ .p_w, .insr } else .{ .p_w, .extr },
8732 registerAlias(dst_reg, 4),
8733 registerAlias(src_reg, 4),
77328734 Immediate.u(0),
77338735 ),
7734 4 => .movd,
7735 8 => .movq,
8736 4 => .{ ._d, .mov },
8737 8 => .{ ._q, .mov },
77368738 else => return self.fail(
77378739 "unsupported register copy from {s} to {s}",
77388740 .{ @tagName(src_reg), @tagName(dst_reg) },
......@@ -7759,7 +8761,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
77598761 });
77608762 if (ty.isRuntimeFloat() and ty.floatBits(self.target.*) == 16)
77618763 try self.asmRegisterMemoryImmediate(
7762 .pinsrw,
8764 .{ .p_w, .insr },
77638765 registerAlias(dst_reg, abi_size),
77648766 src_mem,
77658767 Immediate.u(0),
......@@ -7769,10 +8771,14 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
77698771 switch (src_mcv) {
77708772 .register_offset => |reg_off| switch (reg_off.off) {
77718773 0 => return self.genSetReg(dst_reg, ty, .{ .register = reg_off.reg }),
7772 else => .lea,
8774 else => .{ ._, .lea },
77738775 },
7774 .indirect, .load_frame => try self.movMirTag(ty),
7775 .lea_frame => .lea,
8776 .indirect => try self.movMirTag(ty, false),
8777 .load_frame => |frame_addr| try self.movMirTag(
8778 ty,
8779 self.getFrameAddrAlignment(frame_addr) >= ty.abiAlignment(self.target.*),
8780 ),
8781 .lea_frame => .{ ._, .lea },
77768782 else => unreachable,
77778783 },
77788784 registerAlias(dst_reg, abi_size),
......@@ -7788,14 +8794,18 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
77888794 });
77898795 return if (ty.isRuntimeFloat() and ty.floatBits(self.target.*) == 16)
77908796 self.asmRegisterMemoryImmediate(
7791 .pinsrw,
8797 .{ .p_w, .insr },
77928798 registerAlias(dst_reg, abi_size),
77938799 src_mem,
77948800 Immediate.u(0),
77958801 )
77968802 else
77978803 self.asmRegisterMemory(
7798 try self.movMirTag(ty),
8804 try self.movMirTag(ty, mem.isAlignedGeneric(
8805 u32,
8806 @bitCast(u32, small_addr),
8807 ty.abiAlignment(self.target.*),
8808 )),
77998809 registerAlias(dst_reg, abi_size),
78008810 src_mem,
78018811 );
......@@ -7803,13 +8813,15 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
78038813 .load_direct => |sym_index| if (!ty.isRuntimeFloat()) {
78048814 const atom_index = try self.owner.getSymbolIndex(self);
78058815 _ = try self.addInst(.{
7806 .tag = .mov_linker,
8816 .tag = .mov,
78078817 .ops = .direct_reloc,
7808 .data = .{ .payload = try self.addExtra(Mir.LeaRegisterReloc{
7809 .reg = @enumToInt(dst_reg.to64()),
7810 .atom_index = atom_index,
7811 .sym_index = sym_index,
7812 }) },
8818 .data = .{ .rx = .{
8819 .r1 = dst_reg.to64(),
8820 .payload = try self.addExtra(Mir.Reloc{
8821 .atom_index = atom_index,
8822 .sym_index = sym_index,
8823 }),
8824 } },
78138825 });
78148826 return;
78158827 },
......@@ -7826,14 +8838,14 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
78268838 });
78278839 if (ty.isRuntimeFloat() and ty.floatBits(self.target.*) == 16)
78288840 try self.asmRegisterMemoryImmediate(
7829 .pinsrw,
8841 .{ .p_w, .insr },
78308842 registerAlias(dst_reg, abi_size),
78318843 src_mem,
78328844 Immediate.u(0),
78338845 )
78348846 else
78358847 try self.asmRegisterMemory(
7836 try self.movMirTag(ty),
8848 try self.movMirTag(ty, false),
78378849 registerAlias(dst_reg, abi_size),
78388850 src_mem,
78398851 );
......@@ -7842,8 +8854,8 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
78428854 const atom_index = try self.owner.getSymbolIndex(self);
78438855 _ = try self.addInst(.{
78448856 .tag = switch (src_mcv) {
7845 .lea_direct => .lea_linker,
7846 .lea_got => .mov_linker,
8857 .lea_direct => .lea,
8858 .lea_got => .mov,
78478859 else => unreachable,
78488860 },
78498861 .ops = switch (src_mcv) {
......@@ -7851,27 +8863,31 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
78518863 .lea_got => .got_reloc,
78528864 else => unreachable,
78538865 },
7854 .data = .{ .payload = try self.addExtra(Mir.LeaRegisterReloc{
7855 .reg = @enumToInt(dst_reg.to64()),
7856 .atom_index = atom_index,
7857 .sym_index = sym_index,
7858 }) },
8866 .data = .{ .rx = .{
8867 .r1 = dst_reg.to64(),
8868 .payload = try self.addExtra(Mir.Reloc{
8869 .atom_index = atom_index,
8870 .sym_index = sym_index,
8871 }),
8872 } },
78598873 });
78608874 },
78618875 .lea_tlv => |sym_index| {
78628876 const atom_index = try self.owner.getSymbolIndex(self);
78638877 if (self.bin_file.cast(link.File.MachO)) |_| {
78648878 _ = try self.addInst(.{
7865 .tag = .lea_linker,
8879 .tag = .lea,
78668880 .ops = .tlv_reloc,
7867 .data = .{ .payload = try self.addExtra(Mir.LeaRegisterReloc{
7868 .reg = @enumToInt(Register.rdi),
7869 .atom_index = atom_index,
7870 .sym_index = sym_index,
7871 }) },
8881 .data = .{ .rx = .{
8882 .r1 = .rdi,
8883 .payload = try self.addExtra(Mir.Reloc{
8884 .atom_index = atom_index,
8885 .sym_index = sym_index,
8886 }),
8887 } },
78728888 });
78738889 // TODO: spill registers before calling
7874 try self.asmMemory(.call, Memory.sib(.qword, .{ .base = .{ .reg = .rdi } }));
8890 try self.asmMemory(.{ ._, .call }, Memory.sib(.qword, .{ .base = .{ .reg = .rdi } }));
78758891 try self.genSetReg(dst_reg.to64(), Type.usize, .{ .register = .rax });
78768892 } else return self.fail("TODO emit ptr to TLV sequence on {s}", .{
78778893 @tagName(self.bin_file.tag),
......@@ -7898,7 +8914,7 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
78988914 else
78998915 Immediate.u(@intCast(u32, imm));
79008916 try self.asmMemoryImmediate(
7901 .mov,
8917 .{ ._, .mov },
79028918 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = base, .disp = disp }),
79038919 immediate,
79048920 );
......@@ -7906,14 +8922,14 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
79068922 3, 5...7 => unreachable,
79078923 else => if (math.cast(i32, @bitCast(i64, imm))) |small| {
79088924 try self.asmMemoryImmediate(
7909 .mov,
8925 .{ ._, .mov },
79108926 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = base, .disp = disp }),
79118927 Immediate.s(small),
79128928 );
79138929 } else {
79148930 var offset: i32 = 0;
79158931 while (offset < abi_size) : (offset += 4) try self.asmMemoryImmediate(
7916 .mov,
8932 .{ ._, .mov },
79178933 Memory.sib(.dword, .{ .base = base, .disp = disp + offset }),
79188934 if (ty.isSignedInt())
79198935 Immediate.s(@truncate(
......@@ -7936,14 +8952,31 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
79368952 );
79378953 if (ty.isRuntimeFloat() and ty.floatBits(self.target.*) == 16)
79388954 try self.asmMemoryRegisterImmediate(
7939 .pextrw,
8955 .{ .p_w, .extr },
79408956 dst_mem,
7941 registerAlias(src_reg, abi_size),
8957 src_reg.to128(),
79428958 Immediate.u(0),
79438959 )
79448960 else
79458961 try self.asmMemoryRegister(
7946 try self.movMirTag(ty),
8962 try self.movMirTag(ty, switch (base) {
8963 .none => mem.isAlignedGeneric(
8964 u32,
8965 @bitCast(u32, disp),
8966 ty.abiAlignment(self.target.*),
8967 ),
8968 .reg => |reg| switch (reg) {
8969 .es, .cs, .ss, .ds => mem.isAlignedGeneric(
8970 u32,
8971 @bitCast(u32, disp),
8972 ty.abiAlignment(self.target.*),
8973 ),
8974 else => false,
8975 },
8976 .frame => |frame_index| self.getFrameAddrAlignment(
8977 .{ .index = frame_index, .off = disp },
8978 ) >= ty.abiAlignment(self.target.*),
8979 }),
79478980 dst_mem,
79488981 registerAlias(src_reg, abi_size),
79498982 );
......@@ -8015,7 +9048,7 @@ fn genInlineMemcpyRegisterRegister(
80159048 while (remainder > 0) {
80169049 const nearest_power_of_two = @as(u6, 1) << math.log2_int(u3, @intCast(u3, remainder));
80179050 try self.asmMemoryRegister(
8018 .mov,
9051 .{ ._, .mov },
80199052 Memory.sib(Memory.PtrSize.fromSize(nearest_power_of_two), .{
80209053 .base = dst_reg,
80219054 .disp = -next_offset,
......@@ -8024,7 +9057,7 @@ fn genInlineMemcpyRegisterRegister(
80249057 );
80259058
80269059 if (nearest_power_of_two > 1) {
8027 try self.genShiftBinOpMir(.shr, ty, .{ .register = tmp_reg }, .{
9060 try self.genShiftBinOpMir(.{ ._r, .sh }, ty, .{ .register = tmp_reg }, .{
80289061 .immediate = nearest_power_of_two * 8,
80299062 });
80309063 }
......@@ -8035,8 +9068,8 @@ fn genInlineMemcpyRegisterRegister(
80359068 } else {
80369069 try self.asmMemoryRegister(
80379070 switch (src_reg.class()) {
8038 .general_purpose, .segment => .mov,
8039 .floating_point => .movss,
9071 .general_purpose, .segment => .{ ._, .mov },
9072 .floating_point => .{ ._ss, .mov },
80409073 },
80419074 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = dst_reg, .disp = -offset }),
80429075 registerAlias(src_reg, abi_size),
......@@ -8049,11 +9082,7 @@ fn genInlineMemcpy(self: *Self, dst_ptr: MCValue, src_ptr: MCValue, len: MCValue
80499082 try self.genSetReg(.rdi, Type.usize, dst_ptr);
80509083 try self.genSetReg(.rsi, Type.usize, src_ptr);
80519084 try self.genSetReg(.rcx, Type.usize, len);
8052 _ = try self.addInst(.{
8053 .tag = .movs,
8054 .ops = .string,
8055 .data = .{ .string = .{ .repeat = .rep, .width = .b } },
8056 });
9085 try self.asmOpOnly(.{ .@"rep _sb", .mov });
80579086}
80589087
80599088fn genInlineMemset(self: *Self, dst_ptr: MCValue, value: MCValue, len: MCValue) InnerError!void {
......@@ -8061,11 +9090,7 @@ fn genInlineMemset(self: *Self, dst_ptr: MCValue, value: MCValue, len: MCValue)
80619090 try self.genSetReg(.rdi, Type.usize, dst_ptr);
80629091 try self.genSetReg(.al, Type.u8, value);
80639092 try self.genSetReg(.rcx, Type.usize, len);
8064 _ = try self.addInst(.{
8065 .tag = .stos,
8066 .ops = .string,
8067 .data = .{ .string = .{ .repeat = .rep, .width = .b } },
8068 });
9093 try self.asmOpOnly(.{ .@"rep _sb", .sto });
80699094}
80709095
80719096fn genLazySymbolRef(
......@@ -8083,14 +9108,14 @@ fn genLazySymbolRef(
80839108 const got_mem =
80849109 Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) });
80859110 switch (tag) {
8086 .lea, .mov => try self.asmRegisterMemory(.mov, reg.to64(), got_mem),
8087 .call => try self.asmMemory(.call, got_mem),
9111 .lea, .mov => try self.asmRegisterMemory(.{ ._, .mov }, reg.to64(), got_mem),
9112 .call => try self.asmMemory(.{ ._, .call }, got_mem),
80889113 else => unreachable,
80899114 }
80909115 switch (tag) {
80919116 .lea, .call => {},
80929117 .mov => try self.asmRegisterMemory(
8093 tag,
9118 .{ ._, tag },
80949119 reg.to64(),
80959120 Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }),
80969121 ),
......@@ -8107,7 +9132,7 @@ fn genLazySymbolRef(
81079132 }
81089133 switch (tag) {
81099134 .lea, .mov => {},
8110 .call => try self.asmRegister(.call, reg),
9135 .call => try self.asmRegister(.{ ._, .call }, reg),
81119136 else => unreachable,
81129137 }
81139138 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
......@@ -8121,7 +9146,7 @@ fn genLazySymbolRef(
81219146 }
81229147 switch (tag) {
81239148 .lea, .mov => {},
8124 .call => try self.asmRegister(.call, reg),
9149 .call => try self.asmRegister(.{ ._, .call }, reg),
81259150 else => unreachable,
81269151 }
81279152 } else {
......@@ -8164,7 +9189,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
81649189 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
81659190
81669191 const dest = try self.allocRegOrMem(inst, true);
8167 try self.genCopy(self.air.typeOfIndex(inst), dest, operand);
9192 try self.genCopy(if (!dest.isMemory() or operand.isMemory()) dst_ty else src_ty, dest, operand);
81689193 break :result dest;
81699194 };
81709195 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -8226,13 +9251,13 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void {
82269251
82279252 try self.asmRegisterRegister(switch (dst_ty.floatBits(self.target.*)) {
82289253 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse))
8229 .cvtsi2ss
9254 .{ ._, .cvtsi2ss }
82309255 else
82319256 return self.fail("TODO implement airIntToFloat from {} to {} without sse", .{
82329257 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
82339258 }),
82349259 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2))
8235 .cvtsi2sd
9260 .{ ._, .cvtsi2sd }
82369261 else
82379262 return self.fail("TODO implement airIntToFloat from {} to {} without sse2", .{
82389263 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
......@@ -8272,7 +9297,7 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {
82729297 },
82739298 };
82749299 try self.asmMemory(
8275 .fld,
9300 .{ .f_, .ld },
82769301 Memory.sib(Memory.PtrSize.fromSize(src_abi_size), .{
82779302 .base = .{ .frame = frame_addr.index },
82789303 .disp = frame_addr.off,
......@@ -8282,7 +9307,7 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {
82829307 // convert
82839308 const stack_dst = try self.allocRegOrMem(inst, false);
82849309 try self.asmMemory(
8285 .fisttp,
9310 .{ .f_p, .istt },
82869311 Memory.sib(Memory.PtrSize.fromSize(dst_abi_size), .{
82879312 .base = .{ .frame = stack_dst.load_frame.index },
82889313 .disp = stack_dst.load_frame.off,
......@@ -8338,16 +9363,11 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
83389363 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
83399364
83409365 try self.spillEflagsIfOccupied();
8341 if (val_abi_size <= 8) {
8342 _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{
8343 .r = registerAlias(new_reg.?, val_abi_size),
8344 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
8345 } } });
8346 } else {
8347 _ = try self.addInst(.{ .tag = .cmpxchgb, .ops = .lock_m_sib, .data = .{
8348 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
8349 } });
8350 }
9366 if (val_abi_size <= 8) try self.asmMemoryRegister(
9367 .{ .@"lock _", .cmpxchg },
9368 ptr_mem,
9369 registerAlias(new_reg.?, val_abi_size),
9370 ) else try self.asmMemory(.{ .@"lock _16b", .cmpxchg }, ptr_mem);
83519371
83529372 const result: MCValue = result: {
83539373 if (self.liveness.isUnused(inst)) break :result .unreach;
......@@ -8445,16 +9465,17 @@ fn atomicOp(
84459465
84469466 try self.genSetReg(dst_reg, val_ty, val_mcv);
84479467 if (rmw_op == std.builtin.AtomicRmwOp.Sub and tag == .xadd) {
8448 try self.genUnOpMir(.neg, val_ty, dst_mcv);
9468 try self.genUnOpMir(.{ ._, .neg }, val_ty, dst_mcv);
84499469 }
8450 _ = try self.addInst(.{ .tag = tag, .ops = switch (tag) {
8451 .mov, .xchg => .mr_sib,
8452 .xadd, .add, .sub, .@"and", .@"or", .xor => .lock_mr_sib,
8453 else => unreachable,
8454 }, .data = .{ .rx = .{
8455 .r = registerAlias(dst_reg, val_abi_size),
8456 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
8457 } } });
9470 try self.asmMemoryRegister(
9471 switch (tag) {
9472 .mov, .xchg => .{ ._, tag },
9473 .xadd, .add, .sub, .@"and", .@"or", .xor => .{ .@"lock _", tag },
9474 else => unreachable,
9475 },
9476 ptr_mem,
9477 registerAlias(dst_reg, val_abi_size),
9478 );
84589479
84599480 return if (unused) .unreach else dst_mcv;
84609481 },
......@@ -8464,22 +9485,22 @@ fn atomicOp(
84649485 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
84659486 defer self.register_manager.unlockReg(tmp_lock);
84669487
8467 try self.asmRegisterMemory(.mov, registerAlias(.rax, val_abi_size), ptr_mem);
9488 try self.asmRegisterMemory(.{ ._, .mov }, registerAlias(.rax, val_abi_size), ptr_mem);
84689489 const loop = @intCast(u32, self.mir_instructions.len);
84699490 if (rmw_op != std.builtin.AtomicRmwOp.Xchg) {
84709491 try self.genSetReg(tmp_reg, val_ty, .{ .register = .rax });
84719492 }
84729493 if (rmw_op) |op| switch (op) {
84739494 .Xchg => try self.genSetReg(tmp_reg, val_ty, val_mcv),
8474 .Add => try self.genBinOpMir(.add, val_ty, tmp_mcv, val_mcv),
8475 .Sub => try self.genBinOpMir(.sub, val_ty, tmp_mcv, val_mcv),
8476 .And => try self.genBinOpMir(.@"and", val_ty, tmp_mcv, val_mcv),
9495 .Add => try self.genBinOpMir(.{ ._, .add }, val_ty, tmp_mcv, val_mcv),
9496 .Sub => try self.genBinOpMir(.{ ._, .sub }, val_ty, tmp_mcv, val_mcv),
9497 .And => try self.genBinOpMir(.{ ._, .@"and" }, val_ty, tmp_mcv, val_mcv),
84779498 .Nand => {
8478 try self.genBinOpMir(.@"and", val_ty, tmp_mcv, val_mcv);
8479 try self.genUnOpMir(.not, val_ty, tmp_mcv);
9499 try self.genBinOpMir(.{ ._, .@"and" }, val_ty, tmp_mcv, val_mcv);
9500 try self.genUnOpMir(.{ ._, .not }, val_ty, tmp_mcv);
84809501 },
8481 .Or => try self.genBinOpMir(.@"or", val_ty, tmp_mcv, val_mcv),
8482 .Xor => try self.genBinOpMir(.xor, val_ty, tmp_mcv, val_mcv),
9502 .Or => try self.genBinOpMir(.{ ._, .@"or" }, val_ty, tmp_mcv, val_mcv),
9503 .Xor => try self.genBinOpMir(.{ ._, .xor }, val_ty, tmp_mcv, val_mcv),
84839504 .Min, .Max => {
84849505 const cc: Condition = switch (if (val_ty.isAbiInt())
84859506 val_ty.intInfo(self.target.*).signedness
......@@ -8497,7 +9518,7 @@ fn atomicOp(
84979518 },
84989519 };
84999520
8500 try self.genBinOpMir(.cmp, val_ty, tmp_mcv, val_mcv);
9521 try self.genBinOpMir(.{ ._, .cmp }, val_ty, tmp_mcv, val_mcv);
85019522 const cmov_abi_size = @max(val_abi_size, 2);
85029523 switch (val_mcv) {
85039524 .register => |val_reg| try self.asmCmovccRegisterRegister(
......@@ -8521,19 +9542,20 @@ fn atomicOp(
85219542 }
85229543 },
85239544 };
8524 _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{
8525 .r = registerAlias(tmp_reg, val_abi_size),
8526 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
8527 } } });
9545 try self.asmMemoryRegister(
9546 .{ .@"lock _", .cmpxchg },
9547 ptr_mem,
9548 registerAlias(tmp_reg, val_abi_size),
9549 );
85289550 _ = try self.asmJccReloc(loop, .ne);
85299551 return if (unused) .unreach else .{ .register = .rax };
85309552 } else {
8531 try self.asmRegisterMemory(.mov, .rax, Memory.sib(.qword, .{
9553 try self.asmRegisterMemory(.{ ._, .mov }, .rax, Memory.sib(.qword, .{
85329554 .base = ptr_mem.sib.base,
85339555 .scale_index = ptr_mem.scaleIndex(),
85349556 .disp = ptr_mem.sib.disp + 0,
85359557 }));
8536 try self.asmRegisterMemory(.mov, .rdx, Memory.sib(.qword, .{
9558 try self.asmRegisterMemory(.{ ._, .mov }, .rdx, Memory.sib(.qword, .{
85379559 .base = ptr_mem.sib.base,
85389560 .scale_index = ptr_mem.scaleIndex(),
85399561 .disp = ptr_mem.sib.disp + 8,
......@@ -8548,53 +9570,51 @@ fn atomicOp(
85489570 const val_lo_mem = val_mem_mcv.mem(.qword);
85499571 const val_hi_mem = val_mem_mcv.address().offset(8).deref().mem(.qword);
85509572 if (rmw_op != std.builtin.AtomicRmwOp.Xchg) {
8551 try self.asmRegisterRegister(.mov, .rbx, .rax);
8552 try self.asmRegisterRegister(.mov, .rcx, .rdx);
9573 try self.asmRegisterRegister(.{ ._, .mov }, .rbx, .rax);
9574 try self.asmRegisterRegister(.{ ._, .mov }, .rcx, .rdx);
85539575 }
85549576 if (rmw_op) |op| switch (op) {
85559577 .Xchg => {
8556 try self.asmRegisterMemory(.mov, .rbx, val_lo_mem);
8557 try self.asmRegisterMemory(.mov, .rcx, val_hi_mem);
9578 try self.asmRegisterMemory(.{ ._, .mov }, .rbx, val_lo_mem);
9579 try self.asmRegisterMemory(.{ ._, .mov }, .rcx, val_hi_mem);
85589580 },
85599581 .Add => {
8560 try self.asmRegisterMemory(.add, .rbx, val_lo_mem);
8561 try self.asmRegisterMemory(.adc, .rcx, val_hi_mem);
9582 try self.asmRegisterMemory(.{ ._, .add }, .rbx, val_lo_mem);
9583 try self.asmRegisterMemory(.{ ._, .adc }, .rcx, val_hi_mem);
85629584 },
85639585 .Sub => {
8564 try self.asmRegisterMemory(.sub, .rbx, val_lo_mem);
8565 try self.asmRegisterMemory(.sbb, .rcx, val_hi_mem);
9586 try self.asmRegisterMemory(.{ ._, .sub }, .rbx, val_lo_mem);
9587 try self.asmRegisterMemory(.{ ._, .sbb }, .rcx, val_hi_mem);
85669588 },
85679589 .And => {
8568 try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem);
8569 try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem);
9590 try self.asmRegisterMemory(.{ ._, .@"and" }, .rbx, val_lo_mem);
9591 try self.asmRegisterMemory(.{ ._, .@"and" }, .rcx, val_hi_mem);
85709592 },
85719593 .Nand => {
8572 try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem);
8573 try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem);
8574 try self.asmRegister(.not, .rbx);
8575 try self.asmRegister(.not, .rcx);
9594 try self.asmRegisterMemory(.{ ._, .@"and" }, .rbx, val_lo_mem);
9595 try self.asmRegisterMemory(.{ ._, .@"and" }, .rcx, val_hi_mem);
9596 try self.asmRegister(.{ ._, .not }, .rbx);
9597 try self.asmRegister(.{ ._, .not }, .rcx);
85769598 },
85779599 .Or => {
8578 try self.asmRegisterMemory(.@"or", .rbx, val_lo_mem);
8579 try self.asmRegisterMemory(.@"or", .rcx, val_hi_mem);
9600 try self.asmRegisterMemory(.{ ._, .@"or" }, .rbx, val_lo_mem);
9601 try self.asmRegisterMemory(.{ ._, .@"or" }, .rcx, val_hi_mem);
85809602 },
85819603 .Xor => {
8582 try self.asmRegisterMemory(.xor, .rbx, val_lo_mem);
8583 try self.asmRegisterMemory(.xor, .rcx, val_hi_mem);
9604 try self.asmRegisterMemory(.{ ._, .xor }, .rbx, val_lo_mem);
9605 try self.asmRegisterMemory(.{ ._, .xor }, .rcx, val_hi_mem);
85849606 },
85859607 else => return self.fail("TODO implement x86 atomic loop for {} {s}", .{
85869608 val_ty.fmt(self.bin_file.options.module.?), @tagName(op),
85879609 }),
85889610 };
8589 _ = try self.addInst(.{ .tag = .cmpxchgb, .ops = .lock_m_sib, .data = .{
8590 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
8591 } });
9611 try self.asmMemory(.{ .@"lock _16b", .cmpxchg }, ptr_mem);
85929612 _ = try self.asmJccReloc(loop, .ne);
85939613
85949614 if (unused) return .unreach;
85959615 const dst_mcv = try self.allocTempRegOrMem(val_ty, false);
85969616 try self.asmMemoryRegister(
8597 .mov,
9617 .{ ._, .mov },
85989618 Memory.sib(.qword, .{
85999619 .base = .{ .frame = dst_mcv.load_frame.index },
86009620 .disp = dst_mcv.load_frame.off + 0,
......@@ -8602,7 +9622,7 @@ fn atomicOp(
86029622 .rax,
86039623 );
86049624 try self.asmMemoryRegister(
8605 .mov,
9625 .{ ._, .mov },
86069626 Memory.sib(.qword, .{
86079627 .base = .{ .frame = dst_mcv.load_frame.index },
86089628 .disp = dst_mcv.load_frame.off + 8,
......@@ -8754,8 +9774,13 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
87549774 .off = elem_abi_size,
87559775 } });
87569776
8757 try self.genBinOpMir(.sub, Type.usize, len_mcv, .{ .immediate = 1 });
8758 try self.asmRegisterRegisterImmediate(.imul, len_reg, len_reg, Immediate.u(elem_abi_size));
9777 try self.genBinOpMir(.{ ._, .sub }, Type.usize, len_mcv, .{ .immediate = 1 });
9778 try self.asmRegisterRegisterImmediate(
9779 .{ .i_, .mul },
9780 len_reg,
9781 len_reg,
9782 Immediate.u(elem_abi_size),
9783 );
87599784 try self.genInlineMemcpy(second_elem_ptr_mcv, ptr, len_mcv);
87609785
87619786 try self.performReloc(skip_reloc);
......@@ -8893,7 +9918,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
88939918 try self.truncateRegister(err_ty, err_reg.to32());
88949919
88959920 try self.asmRegisterMemory(
8896 .mov,
9921 .{ ._, .mov },
88979922 start_reg.to32(),
88989923 Memory.sib(.dword, .{
88999924 .base = .{ .reg = addr_reg.to64() },
......@@ -8902,7 +9927,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
89029927 }),
89039928 );
89049929 try self.asmRegisterMemory(
8905 .mov,
9930 .{ ._, .mov },
89069931 end_reg.to32(),
89079932 Memory.sib(.dword, .{
89089933 .base = .{ .reg = addr_reg.to64() },
......@@ -8910,9 +9935,9 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
89109935 .disp = 8,
89119936 }),
89129937 );
8913 try self.asmRegisterRegister(.sub, end_reg.to32(), start_reg.to32());
9938 try self.asmRegisterRegister(.{ ._, .sub }, end_reg.to32(), start_reg.to32());
89149939 try self.asmRegisterMemory(
8915 .lea,
9940 .{ ._, .lea },
89169941 start_reg.to64(),
89179942 Memory.sib(.byte, .{
89189943 .base = .{ .reg = addr_reg.to64() },
......@@ -8921,7 +9946,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
89219946 }),
89229947 );
89239948 try self.asmRegisterMemory(
8924 .lea,
9949 .{ ._, .lea },
89259950 end_reg.to32(),
89269951 Memory.sib(.byte, .{
89279952 .base = .{ .reg = end_reg.to64() },
......@@ -8931,7 +9956,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
89319956
89329957 const dst_mcv = try self.allocRegOrMem(inst, false);
89339958 try self.asmMemoryRegister(
8934 .mov,
9959 .{ ._, .mov },
89359960 Memory.sib(.qword, .{
89369961 .base = .{ .frame = dst_mcv.load_frame.index },
89379962 .disp = dst_mcv.load_frame.off,
......@@ -8939,7 +9964,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
89399964 start_reg.to64(),
89409965 );
89419966 try self.asmMemoryRegister(
8942 .mov,
9967 .{ ._, .mov },
89439968 Memory.sib(.qword, .{
89449969 .base = .{ .frame = dst_mcv.load_frame.index },
89459970 .disp = dst_mcv.load_frame.off + 8,
......@@ -9035,13 +10060,13 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
903510060 try self.truncateRegister(elem_ty, elem_reg);
903610061 }
903710062 if (elem_bit_off > 0) try self.genShiftBinOpMir(
9038 .shl,
10063 .{ ._l, .sh },
903910064 elem_ty,
904010065 .{ .register = elem_reg },
904110066 .{ .immediate = elem_bit_off },
904210067 );
904310068 try self.genBinOpMir(
9044 .@"or",
10069 .{ ._, .@"or" },
904510070 elem_ty,
904610071 .{ .load_frame = .{ .index = frame_index, .off = elem_byte_off } },
904710072 .{ .register = elem_reg },
......@@ -9052,13 +10077,13 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
905210077 try self.truncateRegister(elem_ty, registerAlias(reg, elem_abi_size));
905310078 }
905410079 try self.genShiftBinOpMir(
9055 .shr,
10080 .{ ._r, .sh },
905610081 elem_ty,
905710082 .{ .register = reg },
905810083 .{ .immediate = elem_abi_bits - elem_bit_off },
905910084 );
906010085 try self.genBinOpMir(
9061 .@"or",
10086 .{ ._, .@"or" },
906210087 elem_ty,
906310088 .{ .load_frame = .{
906410089 .index = frame_index,
......@@ -9130,9 +10155,150 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {
913010155fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void {
913110156 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
913210157 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
9133 _ = extra;
9134 return self.fail("TODO implement airMulAdd for x86_64", .{});
9135 //return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand });
10158 const ty = self.air.typeOfIndex(inst);
10159
10160 if (!self.hasFeature(.fma)) return self.fail("TODO implement airMulAdd for {}", .{
10161 ty.fmt(self.bin_file.options.module.?),
10162 });
10163
10164 const ops = [3]Air.Inst.Ref{ extra.lhs, extra.rhs, pl_op.operand };
10165 var mcvs: [3]MCValue = undefined;
10166 var locks = [1]?RegisterManager.RegisterLock{null} ** 3;
10167 defer for (locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock);
10168 var order = [1]u2{0} ** 3;
10169 var unused = std.StaticBitSet(3).initFull();
10170 for (ops, &mcvs, &locks, 0..) |op, *mcv, *lock, op_i| {
10171 const op_index = @intCast(u2, op_i);
10172 mcv.* = try self.resolveInst(op);
10173 if (unused.isSet(0) and mcv.isRegister() and self.reuseOperand(inst, op, op_index, mcv.*)) {
10174 order[op_index] = 1;
10175 unused.unset(0);
10176 } else if (unused.isSet(2) and mcv.isMemory()) {
10177 order[op_index] = 3;
10178 unused.unset(2);
10179 }
10180 switch (mcv.*) {
10181 .register => |reg| lock.* = self.register_manager.lockReg(reg),
10182 else => {},
10183 }
10184 }
10185 for (&order, &mcvs, &locks) |*mop_index, *mcv, *lock| {
10186 if (mop_index.* != 0) continue;
10187 mop_index.* = 1 + @intCast(u2, unused.toggleFirstSet().?);
10188 if (mop_index.* > 1 and mcv.isRegister()) continue;
10189 const reg = try self.copyToTmpRegister(ty, mcv.*);
10190 mcv.* = .{ .register = reg };
10191 if (lock.*) |old_lock| self.register_manager.unlockReg(old_lock);
10192 lock.* = self.register_manager.lockRegAssumeUnused(reg);
10193 }
10194
10195 const mir_tag = if (@as(
10196 ?Mir.Inst.FixedTag,
10197 if (mem.eql(u2, &order, &.{ 1, 3, 2 }) or mem.eql(u2, &order, &.{ 3, 1, 2 }))
10198 switch (ty.zigTypeTag()) {
10199 .Float => switch (ty.floatBits(self.target.*)) {
10200 32 => .{ .v_ss, .fmadd132 },
10201 64 => .{ .v_sd, .fmadd132 },
10202 16, 80, 128 => null,
10203 else => unreachable,
10204 },
10205 .Vector => switch (ty.childType().zigTypeTag()) {
10206 .Float => switch (ty.childType().floatBits(self.target.*)) {
10207 32 => switch (ty.vectorLen()) {
10208 1 => .{ .v_ss, .fmadd132 },
10209 2...8 => .{ .v_ps, .fmadd132 },
10210 else => null,
10211 },
10212 64 => switch (ty.vectorLen()) {
10213 1 => .{ .v_sd, .fmadd132 },
10214 2...4 => .{ .v_pd, .fmadd132 },
10215 else => null,
10216 },
10217 16, 80, 128 => null,
10218 else => unreachable,
10219 },
10220 else => unreachable,
10221 },
10222 else => unreachable,
10223 }
10224 else if (mem.eql(u2, &order, &.{ 2, 1, 3 }) or mem.eql(u2, &order, &.{ 1, 2, 3 }))
10225 switch (ty.zigTypeTag()) {
10226 .Float => switch (ty.floatBits(self.target.*)) {
10227 32 => .{ .v_ss, .fmadd213 },
10228 64 => .{ .v_sd, .fmadd213 },
10229 16, 80, 128 => null,
10230 else => unreachable,
10231 },
10232 .Vector => switch (ty.childType().zigTypeTag()) {
10233 .Float => switch (ty.childType().floatBits(self.target.*)) {
10234 32 => switch (ty.vectorLen()) {
10235 1 => .{ .v_ss, .fmadd213 },
10236 2...8 => .{ .v_ps, .fmadd213 },
10237 else => null,
10238 },
10239 64 => switch (ty.vectorLen()) {
10240 1 => .{ .v_sd, .fmadd213 },
10241 2...4 => .{ .v_pd, .fmadd213 },
10242 else => null,
10243 },
10244 16, 80, 128 => null,
10245 else => unreachable,
10246 },
10247 else => unreachable,
10248 },
10249 else => unreachable,
10250 }
10251 else if (mem.eql(u2, &order, &.{ 2, 3, 1 }) or mem.eql(u2, &order, &.{ 3, 2, 1 }))
10252 switch (ty.zigTypeTag()) {
10253 .Float => switch (ty.floatBits(self.target.*)) {
10254 32 => .{ .v_ss, .fmadd231 },
10255 64 => .{ .v_sd, .fmadd231 },
10256 16, 80, 128 => null,
10257 else => unreachable,
10258 },
10259 .Vector => switch (ty.childType().zigTypeTag()) {
10260 .Float => switch (ty.childType().floatBits(self.target.*)) {
10261 32 => switch (ty.vectorLen()) {
10262 1 => .{ .v_ss, .fmadd231 },
10263 2...8 => .{ .v_ps, .fmadd231 },
10264 else => null,
10265 },
10266 64 => switch (ty.vectorLen()) {
10267 1 => .{ .v_sd, .fmadd231 },
10268 2...4 => .{ .v_pd, .fmadd231 },
10269 else => null,
10270 },
10271 16, 80, 128 => null,
10272 else => unreachable,
10273 },
10274 else => unreachable,
10275 },
10276 else => unreachable,
10277 }
10278 else
10279 unreachable,
10280 )) |tag| tag else return self.fail("TODO implement airMulAdd for {}", .{
10281 ty.fmt(self.bin_file.options.module.?),
10282 });
10283
10284 var mops: [3]MCValue = undefined;
10285 for (order, mcvs) |mop_index, mcv| mops[mop_index - 1] = mcv;
10286
10287 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
10288 const mop1_reg = registerAlias(mops[0].getReg().?, abi_size);
10289 const mop2_reg = registerAlias(mops[1].getReg().?, abi_size);
10290 if (mops[2].isRegister()) try self.asmRegisterRegisterRegister(
10291 mir_tag,
10292 mop1_reg,
10293 mop2_reg,
10294 registerAlias(mops[2].getReg().?, abi_size),
10295 ) else try self.asmRegisterRegisterMemory(
10296 mir_tag,
10297 mop1_reg,
10298 mop2_reg,
10299 mops[2].mem(Memory.PtrSize.fromSize(abi_size)),
10300 );
10301 return self.finishAir(inst, mops[0], ops);
913610302}
913710303
913810304fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {
......@@ -9471,17 +10637,37 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
947110637 switch (int_info.signedness) {
947210638 .signed => {
947310639 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);
9474 try self.genShiftBinOpMir(.sal, Type.isize, .{ .register = reg }, .{ .immediate = shift });
9475 try self.genShiftBinOpMir(.sar, Type.isize, .{ .register = reg }, .{ .immediate = shift });
10640 try self.genShiftBinOpMir(
10641 .{ ._l, .sa },
10642 Type.isize,
10643 .{ .register = reg },
10644 .{ .immediate = shift },
10645 );
10646 try self.genShiftBinOpMir(
10647 .{ ._r, .sa },
10648 Type.isize,
10649 .{ .register = reg },
10650 .{ .immediate = shift },
10651 );
947610652 },
947710653 .unsigned => {
947810654 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);
947910655 const mask = (~@as(u64, 0)) >> shift;
948010656 if (int_info.bits <= 32) {
9481 try self.genBinOpMir(.@"and", Type.u32, .{ .register = reg }, .{ .immediate = mask });
10657 try self.genBinOpMir(
10658 .{ ._, .@"and" },
10659 Type.u32,
10660 .{ .register = reg },
10661 .{ .immediate = mask },
10662 );
948210663 } else {
948310664 const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask });
9484 try self.genBinOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .register = tmp_reg });
10665 try self.genBinOpMir(
10666 .{ ._, .@"and" },
10667 Type.usize,
10668 .{ .register = reg },
10669 .{ .register = tmp_reg },
10670 );
948510671 }
948610672 },
948710673 }
......@@ -9508,3 +10694,13 @@ fn regBitSize(self: *Self, ty: Type) u64 {
950810694fn regExtraBits(self: *Self, ty: Type) u64 {
950910695 return self.regBitSize(ty) - ty.bitSize(self.target.*);
951010696}
10697
10698fn hasFeature(self: *Self, feature: Target.x86.Feature) bool {
10699 return Target.x86.featureSetHas(self.target.cpu.features, feature);
10700}
10701fn hasAnyFeatures(self: *Self, features: anytype) bool {
10702 return Target.x86.featureSetHasAny(self.target.cpu.features, features);
10703}
10704fn hasAllFeatures(self: *Self, features: anytype) bool {
10705 return Target.x86.featureSetHasAll(self.target.cpu.features, features);
10706}
src/arch/x86_64/Emit.zig+141-131
......@@ -18,142 +18,152 @@ pub const Error = Lower.Error || error{
1818};
1919
2020pub fn emitMir(emit: *Emit) Error!void {
21 for (0..emit.lower.mir.instructions.len) |i| {
22 const index = @intCast(Mir.Inst.Index, i);
23 const inst = emit.lower.mir.instructions.get(index);
24
25 const start_offset = @intCast(u32, emit.code.items.len);
26 try emit.code_offset_mapping.putNoClobber(emit.lower.allocator, index, start_offset);
27 for (try emit.lower.lowerMir(inst)) |lower_inst| try lower_inst.encode(emit.code.writer(), .{});
28 const end_offset = @intCast(u32, emit.code.items.len);
29
30 switch (inst.tag) {
31 else => {},
32
33 .jmp_reloc => try emit.relocs.append(emit.lower.allocator, .{
34 .source = start_offset,
35 .target = inst.data.inst,
36 .offset = end_offset - 4,
37 .length = 5,
38 }),
39
40 .call_extern => if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
41 // Add relocation to the decl.
42 const atom_index = macho_file.getAtomIndexForSymbol(
43 .{ .sym_index = inst.data.relocation.atom_index, .file = null },
44 ).?;
45 const target = macho_file.getGlobalByIndex(inst.data.relocation.sym_index);
46 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
47 .type = .branch,
21 for (0..emit.lower.mir.instructions.len) |mir_i| {
22 const mir_index = @intCast(Mir.Inst.Index, mir_i);
23 try emit.code_offset_mapping.putNoClobber(
24 emit.lower.allocator,
25 mir_index,
26 @intCast(u32, emit.code.items.len),
27 );
28 const lowered = try emit.lower.lowerMir(mir_index);
29 var lowered_relocs = lowered.relocs;
30 for (lowered.insts, 0..) |lowered_inst, lowered_index| {
31 const start_offset = @intCast(u32, emit.code.items.len);
32 try lowered_inst.encode(emit.code.writer(), .{});
33 const end_offset = @intCast(u32, emit.code.items.len);
34 while (lowered_relocs.len > 0 and
35 lowered_relocs[0].lowered_inst_index == lowered_index) : ({
36 lowered_relocs = lowered_relocs[1..];
37 }) switch (lowered_relocs[0].target) {
38 .inst => |target| try emit.relocs.append(emit.lower.allocator, .{
39 .source = start_offset,
4840 .target = target,
4941 .offset = end_offset - 4,
50 .addend = 0,
51 .pcrel = true,
52 .length = 2,
53 });
54 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
55 // Add relocation to the decl.
56 const atom_index = coff_file.getAtomIndexForSymbol(
57 .{ .sym_index = inst.data.relocation.atom_index, .file = null },
58 ).?;
59 const target = coff_file.getGlobalByIndex(inst.data.relocation.sym_index);
60 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
61 .type = .direct,
62 .target = target,
63 .offset = end_offset - 4,
64 .addend = 0,
65 .pcrel = true,
66 .length = 2,
67 });
68 } else return emit.fail("TODO implement {} for {}", .{ inst.tag, emit.bin_file.tag }),
69
70 .mov_linker, .lea_linker => if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
71 const metadata =
72 emit.lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data;
73 const atom_index = macho_file.getAtomIndexForSymbol(.{
74 .sym_index = metadata.atom_index,
75 .file = null,
76 }).?;
77 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
78 .type = switch (inst.ops) {
79 .got_reloc => .got,
80 .direct_reloc => .signed,
81 .tlv_reloc => .tlv,
82 else => unreachable,
83 },
84 .target = .{ .sym_index = metadata.sym_index, .file = null },
85 .offset = @intCast(u32, end_offset - 4),
86 .addend = 0,
87 .pcrel = true,
88 .length = 2,
89 });
90 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
91 const metadata =
92 emit.lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data;
93 const atom_index = coff_file.getAtomIndexForSymbol(.{
94 .sym_index = metadata.atom_index,
95 .file = null,
96 }).?;
97 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
98 .type = switch (inst.ops) {
99 .got_reloc => .got,
100 .direct_reloc => .direct,
101 .import_reloc => .import,
102 else => unreachable,
103 },
104 .target = switch (inst.ops) {
105 .got_reloc,
106 .direct_reloc,
107 => .{ .sym_index = metadata.sym_index, .file = null },
108 .import_reloc => coff_file.getGlobalByIndex(metadata.sym_index),
109 else => unreachable,
110 },
111 .offset = @intCast(u32, end_offset - 4),
112 .addend = 0,
113 .pcrel = true,
114 .length = 2,
115 });
116 } else return emit.fail("TODO implement {} for {}", .{ inst.tag, emit.bin_file.tag }),
117
118 .jcc => try emit.relocs.append(emit.lower.allocator, .{
119 .source = start_offset,
120 .target = inst.data.inst_cc.inst,
121 .offset = end_offset - 4,
122 .length = 6,
123 }),
124
125 .dbg_line => try emit.dbgAdvancePCAndLine(
126 inst.data.line_column.line,
127 inst.data.line_column.column,
128 ),
42 .length = @intCast(u5, end_offset - start_offset),
43 }),
44 .linker_extern_fn => |symbol| if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
45 // Add relocation to the decl.
46 const atom_index = macho_file.getAtomIndexForSymbol(
47 .{ .sym_index = symbol.atom_index, .file = null },
48 ).?;
49 const target = macho_file.getGlobalByIndex(symbol.sym_index);
50 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
51 .type = .branch,
52 .target = target,
53 .offset = end_offset - 4,
54 .addend = 0,
55 .pcrel = true,
56 .length = 2,
57 });
58 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
59 // Add relocation to the decl.
60 const atom_index = coff_file.getAtomIndexForSymbol(
61 .{ .sym_index = symbol.atom_index, .file = null },
62 ).?;
63 const target = coff_file.getGlobalByIndex(symbol.sym_index);
64 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
65 .type = .direct,
66 .target = target,
67 .offset = end_offset - 4,
68 .addend = 0,
69 .pcrel = true,
70 .length = 2,
71 });
72 } else return emit.fail("TODO implement extern reloc for {s}", .{
73 @tagName(emit.bin_file.tag),
74 }),
75 .linker_got,
76 .linker_direct,
77 .linker_import,
78 .linker_tlv,
79 => |symbol| if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
80 const atom_index = macho_file.getAtomIndexForSymbol(.{
81 .sym_index = symbol.atom_index,
82 .file = null,
83 }).?;
84 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
85 .type = switch (lowered_relocs[0].target) {
86 .linker_got => .got,
87 .linker_direct => .signed,
88 .linker_tlv => .tlv,
89 else => unreachable,
90 },
91 .target = .{ .sym_index = symbol.sym_index, .file = null },
92 .offset = @intCast(u32, end_offset - 4),
93 .addend = 0,
94 .pcrel = true,
95 .length = 2,
96 });
97 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
98 const atom_index = coff_file.getAtomIndexForSymbol(.{
99 .sym_index = symbol.atom_index,
100 .file = null,
101 }).?;
102 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
103 .type = switch (lowered_relocs[0].target) {
104 .linker_got => .got,
105 .linker_direct => .direct,
106 .linker_import => .import,
107 else => unreachable,
108 },
109 .target = switch (lowered_relocs[0].target) {
110 .linker_got,
111 .linker_direct,
112 => .{ .sym_index = symbol.sym_index, .file = null },
113 .linker_import => coff_file.getGlobalByIndex(symbol.sym_index),
114 else => unreachable,
115 },
116 .offset = @intCast(u32, end_offset - 4),
117 .addend = 0,
118 .pcrel = true,
119 .length = 2,
120 });
121 } else return emit.fail("TODO implement linker reloc for {s}", .{
122 @tagName(emit.bin_file.tag),
123 }),
124 };
125 }
126 std.debug.assert(lowered_relocs.len == 0);
129127
130 .dbg_prologue_end => {
131 switch (emit.debug_output) {
132 .dwarf => |dw| {
133 try dw.setPrologueEnd();
134 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{
135 emit.prev_di_line, emit.prev_di_column,
136 });
137 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
128 if (lowered.insts.len == 0) {
129 const mir_inst = emit.lower.mir.instructions.get(mir_index);
130 switch (mir_inst.tag) {
131 else => unreachable,
132 .pseudo => switch (mir_inst.ops) {
133 else => unreachable,
134 .pseudo_dbg_prologue_end_none => {
135 switch (emit.debug_output) {
136 .dwarf => |dw| {
137 try dw.setPrologueEnd();
138 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{
139 emit.prev_di_line, emit.prev_di_column,
140 });
141 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
142 },
143 .plan9 => {},
144 .none => {},
145 }
138146 },
139 .plan9 => {},
140 .none => {},
141 }
142 },
143
144 .dbg_epilogue_begin => {
145 switch (emit.debug_output) {
146 .dwarf => |dw| {
147 try dw.setEpilogueBegin();
148 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{
149 emit.prev_di_line, emit.prev_di_column,
150 });
151 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
147 .pseudo_dbg_line_line_column => try emit.dbgAdvancePCAndLine(
148 mir_inst.data.line_column.line,
149 mir_inst.data.line_column.column,
150 ),
151 .pseudo_dbg_epilogue_begin_none => {
152 switch (emit.debug_output) {
153 .dwarf => |dw| {
154 try dw.setEpilogueBegin();
155 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{
156 emit.prev_di_line, emit.prev_di_column,
157 });
158 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
159 },
160 .plan9 => {},
161 .none => {},
162 }
152163 },
153 .plan9 => {},
154 .none => {},
155 }
156 },
164 .pseudo_dead_none => {},
165 },
166 }
157167 }
158168 }
159169 try emit.fixupRelocs();
src/arch/x86_64/Encoding.zig+240-107
......@@ -23,6 +23,7 @@ const Data = struct {
2323 opc: [7]u8,
2424 modrm_ext: u3,
2525 mode: Mode,
26 feature: Feature,
2627};
2728
2829pub fn findByMnemonic(
......@@ -57,9 +58,9 @@ pub fn findByMnemonic(
5758 var shortest_len: ?usize = null;
5859 next: for (mnemonic_to_encodings_map[@enumToInt(mnemonic)]) |data| {
5960 switch (data.mode) {
60 .rex => if (!rex_required) continue,
61 .long, .sse_long, .sse2_long => {},
62 else => if (rex_required) continue,
61 .none, .short => if (rex_required) continue,
62 .rex, .rex_short => if (!rex_required) continue,
63 else => {},
6364 }
6465 for (input_ops, data.ops) |input_op, data_op|
6566 if (!input_op.isSubset(data_op)) continue :next;
......@@ -88,28 +89,13 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct {
8889 if (modrm_ext) |ext| if (ext != data.modrm_ext) continue;
8990 if (!std.mem.eql(u8, opc, enc.opcode())) continue;
9091 if (prefixes.rex.w) {
91 switch (data.mode) {
92 .short, .fpu, .sse, .sse2, .sse4_1, .none => continue,
93 .long, .sse_long, .sse2_long, .rex => {},
94 }
92 if (!data.mode.isLong()) continue;
9593 } else if (prefixes.rex.present and !prefixes.rex.isSet()) {
96 switch (data.mode) {
97 .rex => {},
98 else => continue,
99 }
94 if (!data.mode.isRex()) continue;
10095 } else if (prefixes.legacy.prefix_66) {
101 switch (enc.operandBitSize()) {
102 16 => {},
103 else => continue,
104 }
96 if (!data.mode.isShort()) continue;
10597 } else {
106 switch (data.mode) {
107 .none => switch (enc.operandBitSize()) {
108 16 => continue,
109 else => {},
110 },
111 else => continue,
112 }
98 if (data.mode.isShort()) continue;
11399 }
114100 return enc;
115101 };
......@@ -130,30 +116,11 @@ pub fn mandatoryPrefix(encoding: *const Encoding) ?u8 {
130116
131117pub fn modRmExt(encoding: Encoding) u3 {
132118 return switch (encoding.data.op_en) {
133 .m, .mi, .m1, .mc => encoding.data.modrm_ext,
119 .m, .mi, .m1, .mc, .vmi => encoding.data.modrm_ext,
134120 else => unreachable,
135121 };
136122}
137123
138pub fn operandBitSize(encoding: Encoding) u64 {
139 switch (encoding.data.mode) {
140 .short => return 16,
141 .long, .sse_long, .sse2_long => return 64,
142 else => {},
143 }
144 const bit_size: u64 = switch (encoding.data.op_en) {
145 .np => switch (encoding.data.ops[0]) {
146 .o16 => 16,
147 .o32 => 32,
148 .o64 => 64,
149 else => 32,
150 },
151 .td => encoding.data.ops[1].bitSize(),
152 else => encoding.data.ops[0].bitSize(),
153 };
154 return bit_size;
155}
156
157124pub fn format(
158125 encoding: Encoding,
159126 comptime fmt: []const u8,
......@@ -162,14 +129,41 @@ pub fn format(
162129) !void {
163130 _ = options;
164131 _ = fmt;
165 switch (encoding.data.mode) {
166 .long, .sse_long, .sse2_long => try writer.writeAll("REX.W + "),
167 else => {},
168 }
169132
170 for (encoding.opcode()) |byte| {
171 try writer.print("{x:0>2} ", .{byte});
172 }
133 var opc = encoding.opcode();
134 if (encoding.data.mode.isVex()) {
135 try writer.writeAll("VEX.");
136
137 try writer.writeAll(switch (encoding.data.mode) {
138 .vex_128_w0, .vex_128_w1, .vex_128_wig => "128",
139 .vex_256_w0, .vex_256_w1, .vex_256_wig => "256",
140 .vex_lig_w0, .vex_lig_w1, .vex_lig_wig => "LIG",
141 .vex_lz_w0, .vex_lz_w1, .vex_lz_wig => "LZ",
142 else => unreachable,
143 });
144
145 switch (opc[0]) {
146 else => {},
147 0x66, 0xf3, 0xf2 => {
148 try writer.print(".{X:0>2}", .{opc[0]});
149 opc = opc[1..];
150 },
151 }
152
153 try writer.print(".{}", .{std.fmt.fmtSliceHexUpper(opc[0 .. opc.len - 1])});
154 opc = opc[opc.len - 1 ..];
155
156 try writer.writeAll(".W");
157 try writer.writeAll(switch (encoding.data.mode) {
158 .vex_128_w0, .vex_256_w0, .vex_lig_w0, .vex_lz_w0 => "0",
159 .vex_128_w1, .vex_256_w1, .vex_lig_w1, .vex_lz_w1 => "1",
160 .vex_128_wig, .vex_256_wig, .vex_lig_wig, .vex_lz_wig => "IG",
161 else => unreachable,
162 });
163
164 try writer.writeByte(' ');
165 } else if (encoding.data.mode.isLong()) try writer.writeAll("REX.W + ");
166 for (opc) |byte| try writer.print("{x:0>2} ", .{byte});
173167
174168 switch (encoding.data.op_en) {
175169 .np, .fd, .td, .i, .zi, .d => {},
......@@ -183,16 +177,17 @@ pub fn format(
183177 };
184178 try writer.print("+{s} ", .{tag});
185179 },
186 .m, .mi, .m1, .mc => try writer.print("/{d} ", .{encoding.modRmExt()}),
187 .mr, .rm, .rmi, .mri, .mrc => try writer.writeAll("/r "),
180 .m, .mi, .m1, .mc, .vmi => try writer.print("/{d} ", .{encoding.modRmExt()}),
181 .mr, .rm, .rmi, .mri, .mrc, .rvm, .rvmi, .mvr => try writer.writeAll("/r "),
188182 }
189183
190184 switch (encoding.data.op_en) {
191 .i, .d, .zi, .oi, .mi, .rmi, .mri => {
185 .i, .d, .zi, .oi, .mi, .rmi, .mri, .vmi, .rvmi => {
192186 const op = switch (encoding.data.op_en) {
193187 .i, .d => encoding.data.ops[0],
194188 .zi, .oi, .mi => encoding.data.ops[1],
195 .rmi, .mri => encoding.data.ops[2],
189 .rmi, .mri, .vmi => encoding.data.ops[2],
190 .rvmi => encoding.data.ops[3],
196191 else => unreachable,
197192 };
198193 const tag = switch (op) {
......@@ -207,7 +202,7 @@ pub fn format(
207202 };
208203 try writer.print("{s} ", .{tag});
209204 },
210 .np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc => {},
205 .np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc, .rvm, .mvr => {},
211206 }
212207
213208 try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
......@@ -267,44 +262,79 @@ pub const Mnemonic = enum {
267262 // MMX
268263 movd,
269264 // SSE
270 addss,
265 addps, addss,
271266 andps,
272267 andnps,
273268 cmpss,
274269 cvtsi2ss,
275 divss,
276 maxss, minss,
277 movaps, movss, movups,
278 mulss,
270 divps, divss,
271 maxps, maxss,
272 minps, minss,
273 movaps, movhlps, movss, movups,
274 mulps, mulss,
279275 orps,
280 pextrw,
281 pinsrw,
282 sqrtps,
283 sqrtss,
284 subss,
276 pextrw, pinsrw,
277 sqrtps, sqrtss,
278 subps, subss,
285279 ucomiss,
286280 xorps,
287281 // SSE2
288 addsd,
282 addpd, addsd,
289283 andpd,
290284 andnpd,
291285 //cmpsd,
292286 cvtsd2ss, cvtsi2sd, cvtss2sd,
293 divsd,
294 maxsd, minsd,
287 divpd, divsd,
288 maxpd, maxsd,
289 minpd, minsd,
295290 movapd,
296291 movq, //movd, movsd,
297292 movupd,
298 mulsd,
293 mulpd, mulsd,
299294 orpd,
300 sqrtpd,
301 sqrtsd,
302 subsd,
295 pshufhw, pshuflw,
296 psrld, psrlq, psrlw,
297 punpckhbw, punpckhdq, punpckhqdq, punpckhwd,
298 punpcklbw, punpckldq, punpcklqdq, punpcklwd,
299 sqrtpd, sqrtsd,
300 subpd, subsd,
303301 ucomisd,
304302 xorpd,
303 // SSE3
304 movddup, movshdup, movsldup,
305305 // SSE4.1
306 roundss,
307 roundsd,
306 pextrb, pextrd, pextrq,
307 pinsrb, pinsrd, pinsrq,
308 roundpd, roundps, roundsd, roundss,
309 // AVX
310 vaddpd, vaddps, vaddsd, vaddss,
311 vcvtsd2ss, vcvtsi2sd, vcvtsi2ss, vcvtss2sd,
312 vdivpd, vdivps, vdivsd, vdivss,
313 vmaxpd, vmaxps, vmaxsd, vmaxss,
314 vminpd, vminps, vminsd, vminss,
315 vmovapd, vmovaps,
316 vmovddup, vmovhlps,
317 vmovsd,
318 vmovshdup, vmovsldup,
319 vmovss,
320 vmovupd, vmovups,
321 vmulpd, vmulps, vmulsd, vmulss,
322 vpextrb, vpextrd, vpextrq, vpextrw,
323 vpinsrb, vpinsrd, vpinsrq, vpinsrw,
324 vpshufhw, vpshuflw,
325 vpsrld, vpsrlq, vpsrlw,
326 vpunpckhbw, vpunpckhdq, vpunpckhqdq, vpunpckhwd,
327 vpunpcklbw, vpunpckldq, vpunpcklqdq, vpunpcklwd,
328 vroundpd, vroundps, vroundsd, vroundss,
329 vsqrtpd, vsqrtps, vsqrtsd, vsqrtss,
330 vsubpd, vsubps, vsubsd, vsubss,
331 // F16C
332 vcvtph2ps, vcvtps2ph,
333 // FMA
334 vfmadd132pd, vfmadd213pd, vfmadd231pd,
335 vfmadd132ps, vfmadd213ps, vfmadd231ps,
336 vfmadd132sd, vfmadd213sd, vfmadd231sd,
337 vfmadd132ss, vfmadd213ss, vfmadd231ss,
308338 // zig fmt: on
309339};
310340
......@@ -317,6 +347,7 @@ pub const OpEn = enum {
317347 fd, td,
318348 m1, mc, mi, mr, rm,
319349 rmi, mri, mrc,
350 vmi, rvm, rvmi, mvr,
320351 // zig fmt: on
321352};
322353
......@@ -331,12 +362,14 @@ pub const Op = enum {
331362 cl,
332363 r8, r16, r32, r64,
333364 rm8, rm16, rm32, rm64,
334 m8, m16, m32, m64, m80, m128,
365 r32_m8, r32_m16, r64_m16,
366 m8, m16, m32, m64, m80, m128, m256,
335367 rel8, rel16, rel32,
336368 m,
337369 moffs,
338370 sreg,
339371 xmm, xmm_m32, xmm_m64, xmm_m128,
372 ymm, ymm_m256,
340373 // zig fmt: on
341374
342375 pub fn fromOperand(operand: Instruction.Operand) Op {
......@@ -348,6 +381,7 @@ pub const Op = enum {
348381 .segment => return .sreg,
349382 .floating_point => return switch (reg.bitSize()) {
350383 128 => .xmm,
384 256 => .ymm,
351385 else => unreachable,
352386 },
353387 .general_purpose => {
......@@ -381,6 +415,7 @@ pub const Op = enum {
381415 64 => .m64,
382416 80 => .m80,
383417 128 => .m128,
418 256 => .m256,
384419 else => unreachable,
385420 };
386421 },
......@@ -409,16 +444,52 @@ pub const Op = enum {
409444 }
410445 }
411446
412 pub fn bitSize(op: Op) u64 {
447 pub fn immBitSize(op: Op) u64 {
413448 return switch (op) {
414449 .none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
450 .al, .cl, .r8, .rm8, .r32_m8 => unreachable,
451 .ax, .r16, .rm16 => unreachable,
452 .eax, .r32, .rm32, .r32_m16 => unreachable,
453 .rax, .r64, .rm64, .r64_m16 => unreachable,
454 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => unreachable,
455 .ymm, .ymm_m256 => unreachable,
456 .m8, .m16, .m32, .m64, .m80, .m128, .m256 => unreachable,
415457 .unity => 1,
416 .imm8, .imm8s, .al, .cl, .r8, .m8, .rm8, .rel8 => 8,
417 .imm16, .imm16s, .ax, .r16, .m16, .rm16, .rel16 => 16,
418 .imm32, .imm32s, .eax, .r32, .m32, .rm32, .rel32, .xmm_m32 => 32,
419 .imm64, .rax, .r64, .m64, .rm64, .xmm_m64 => 64,
458 .imm8, .imm8s, .rel8 => 8,
459 .imm16, .imm16s, .rel16 => 16,
460 .imm32, .imm32s, .rel32 => 32,
461 .imm64 => 64,
462 };
463 }
464
465 pub fn regBitSize(op: Op) u64 {
466 return switch (op) {
467 .none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
468 .unity, .imm8, .imm8s, .imm16, .imm16s, .imm32, .imm32s, .imm64 => unreachable,
469 .rel8, .rel16, .rel32 => unreachable,
470 .m8, .m16, .m32, .m64, .m80, .m128, .m256 => unreachable,
471 .al, .cl, .r8, .rm8 => 8,
472 .ax, .r16, .rm16 => 16,
473 .eax, .r32, .rm32, .r32_m8, .r32_m16 => 32,
474 .rax, .r64, .rm64, .r64_m16 => 64,
475 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => 128,
476 .ymm, .ymm_m256 => 256,
477 };
478 }
479
480 pub fn memBitSize(op: Op) u64 {
481 return switch (op) {
482 .none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
483 .unity, .imm8, .imm8s, .imm16, .imm16s, .imm32, .imm32s, .imm64 => unreachable,
484 .rel8, .rel16, .rel32 => unreachable,
485 .al, .cl, .r8, .ax, .r16, .eax, .r32, .rax, .r64, .xmm, .ymm => unreachable,
486 .m8, .rm8, .r32_m8 => 8,
487 .m16, .rm16, .r32_m16, .r64_m16 => 16,
488 .m32, .rm32, .xmm_m32 => 32,
489 .m64, .rm64, .xmm_m64 => 64,
420490 .m80 => 80,
421 .m128, .xmm, .xmm_m128 => 128,
491 .m128, .xmm_m128 => 128,
492 .m256, .ymm_m256 => 256,
422493 };
423494 }
424495
......@@ -441,7 +512,9 @@ pub const Op = enum {
441512 .al, .ax, .eax, .rax,
442513 .r8, .r16, .r32, .r64,
443514 .rm8, .rm16, .rm32, .rm64,
515 .r32_m8, .r32_m16, .r64_m16,
444516 .xmm, .xmm_m32, .xmm_m64, .xmm_m128,
517 .ymm, .ymm_m256,
445518 => true,
446519 else => false,
447520 };
......@@ -465,9 +538,11 @@ pub const Op = enum {
465538 // zig fmt: off
466539 return switch (op) {
467540 .rm8, .rm16, .rm32, .rm64,
468 .m8, .m16, .m32, .m64, .m80, .m128,
541 .r32_m8, .r32_m16, .r64_m16,
542 .m8, .m16, .m32, .m64, .m80, .m128, .m256,
469543 .m,
470544 .xmm_m32, .xmm_m64, .xmm_m128,
545 .ymm_m256,
471546 => true,
472547 else => false,
473548 };
......@@ -487,15 +562,10 @@ pub const Op = enum {
487562 .al, .ax, .eax, .rax, .cl => .general_purpose,
488563 .r8, .r16, .r32, .r64 => .general_purpose,
489564 .rm8, .rm16, .rm32, .rm64 => .general_purpose,
565 .r32_m8, .r32_m16, .r64_m16 => .general_purpose,
490566 .sreg => .segment,
491567 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => .floating_point,
492 };
493 }
494
495 pub fn isFloatingPointRegister(op: Op) bool {
496 return switch (op) {
497 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => true,
498 else => false,
568 .ymm, .ymm_m256 => .floating_point,
499569 };
500570 }
501571
......@@ -512,30 +582,27 @@ pub const Op = enum {
512582 if (op.isRegister() and target.isRegister()) {
513583 return switch (target) {
514584 .cl, .al, .ax, .eax, .rax => op == target,
515 else => op.class() == target.class() and switch (target.class()) {
516 .floating_point => true,
517 else => op.bitSize() == target.bitSize(),
518 },
585 else => op.class() == target.class() and op.regBitSize() == target.regBitSize(),
519586 };
520587 }
521588 if (op.isMemory() and target.isMemory()) {
522589 switch (target) {
523590 .m => return true,
524 else => return op.bitSize() == target.bitSize(),
591 else => return op.memBitSize() == target.memBitSize(),
525592 }
526593 }
527594 if (op.isImmediate() and target.isImmediate()) {
528595 switch (target) {
529 .imm64 => if (op.bitSize() <= 64) return true,
530 .imm32s, .rel32 => if (op.bitSize() < 32 or (op.bitSize() == 32 and op.isSigned()))
596 .imm64 => if (op.immBitSize() <= 64) return true,
597 .imm32s, .rel32 => if (op.immBitSize() < 32 or (op.immBitSize() == 32 and op.isSigned()))
531598 return true,
532 .imm32 => if (op.bitSize() <= 32) return true,
533 .imm16s, .rel16 => if (op.bitSize() < 16 or (op.bitSize() == 16 and op.isSigned()))
599 .imm32 => if (op.immBitSize() <= 32) return true,
600 .imm16s, .rel16 => if (op.immBitSize() < 16 or (op.immBitSize() == 16 and op.isSigned()))
534601 return true,
535 .imm16 => if (op.bitSize() <= 16) return true,
536 .imm8s, .rel8 => if (op.bitSize() < 8 or (op.bitSize() == 8 and op.isSigned()))
602 .imm16 => if (op.immBitSize() <= 16) return true,
603 .imm8s, .rel8 => if (op.immBitSize() < 8 or (op.immBitSize() == 8 and op.isSigned()))
537604 return true,
538 .imm8 => if (op.bitSize() <= 8) return true,
605 .imm8 => if (op.immBitSize() <= 8) return true,
539606 else => {},
540607 }
541608 return op == target;
......@@ -547,16 +614,81 @@ pub const Op = enum {
547614};
548615
549616pub const Mode = enum {
617 // zig fmt: off
618 none,
619 short, long,
620 rex, rex_short,
621 vex_128_w0, vex_128_w1, vex_128_wig,
622 vex_256_w0, vex_256_w1, vex_256_wig,
623 vex_lig_w0, vex_lig_w1, vex_lig_wig,
624 vex_lz_w0, vex_lz_w1, vex_lz_wig,
625 // zig fmt: on
626
627 pub fn isShort(mode: Mode) bool {
628 return switch (mode) {
629 .short, .rex_short => true,
630 else => false,
631 };
632 }
633
634 pub fn isLong(mode: Mode) bool {
635 return switch (mode) {
636 .long,
637 .vex_128_w1,
638 .vex_256_w1,
639 .vex_lig_w1,
640 .vex_lz_w1,
641 => true,
642 else => false,
643 };
644 }
645
646 pub fn isRex(mode: Mode) bool {
647 return switch (mode) {
648 else => false,
649 .rex, .rex_short => true,
650 };
651 }
652
653 pub fn isVex(mode: Mode) bool {
654 return switch (mode) {
655 // zig fmt: off
656 else => false,
657 .vex_128_w0, .vex_128_w1, .vex_128_wig,
658 .vex_256_w0, .vex_256_w1, .vex_256_wig,
659 .vex_lig_w0, .vex_lig_w1, .vex_lig_wig,
660 .vex_lz_w0, .vex_lz_w1, .vex_lz_wig,
661 => true,
662 // zig fmt: on
663 };
664 }
665
666 pub fn isVecLong(mode: Mode) bool {
667 return switch (mode) {
668 // zig fmt: off
669 else => unreachable,
670 .vex_128_w0, .vex_128_w1, .vex_128_wig,
671 .vex_lig_w0, .vex_lig_w1, .vex_lig_wig,
672 .vex_lz_w0, .vex_lz_w1, .vex_lz_wig,
673 => false,
674 .vex_256_w0, .vex_256_w1, .vex_256_wig,
675 => true,
676 // zig fmt: on
677 };
678 }
679};
680
681pub const Feature = enum {
550682 none,
551 short,
552 fpu,
553 rex,
554 long,
683 avx,
684 avx2,
685 f16c,
686 fma,
555687 sse,
556 sse_long,
557688 sse2,
558 sse2_long,
689 sse3,
559690 sse4_1,
691 x87,
560692};
561693
562694fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Operand) usize {
......@@ -573,7 +705,7 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op
573705}
574706
575707const mnemonic_to_encodings_map = init: {
576 @setEvalBranchQuota(100_000);
708 @setEvalBranchQuota(20_000);
577709 const encodings = @import("encodings.zig");
578710 var entries = encodings.table;
579711 std.sort.sort(encodings.Entry, &entries, {}, struct {
......@@ -593,6 +725,7 @@ const mnemonic_to_encodings_map = init: {
593725 .opc = undefined,
594726 .modrm_ext = entry[4],
595727 .mode = entry[5],
728 .feature = entry[6],
596729 };
597730 // TODO: use `@memcpy` for these. When I did that, I got a false positive
598731 // compile error for this copy happening at compile time.
src/arch/x86_64/Lower.zig+283-323
......@@ -5,13 +5,22 @@ mir: Mir,
55target: *const std.Target,
66err_msg: ?*ErrorMsg = null,
77src_loc: Module.SrcLoc,
8result: [
8result_insts_len: u8 = undefined,
9result_relocs_len: u8 = undefined,
10result_insts: [
911 std.mem.max(usize, &.{
10 abi.Win64.callee_preserved_regs.len,
11 abi.SysV.callee_preserved_regs.len,
12 2, // cmovcc: cmovcc \ cmovcc
13 3, // setcc: setcc \ setcc \ logicop
14 2, // jcc: jcc \ jcc
15 abi.Win64.callee_preserved_regs.len, // push_regs/pop_regs
16 abi.SysV.callee_preserved_regs.len, // push_regs/pop_regs
1217 })
1318]Instruction = undefined,
14result_len: usize = undefined,
19result_relocs: [
20 std.mem.max(usize, &.{
21 2, // jcc: jcc \ jcc
22 })
23]Reloc = undefined,
1524
1625pub const Error = error{
1726 OutOfMemory,
......@@ -20,155 +29,155 @@ pub const Error = error{
2029 CannotEncode,
2130};
2231
23/// The returned slice is overwritten by the next call to lowerMir.
24pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {
25 lower.result = undefined;
26 errdefer lower.result = undefined;
27 lower.result_len = 0;
28 defer lower.result_len = undefined;
32pub const Reloc = struct {
33 lowered_inst_index: u8,
34 target: Target,
35
36 const Target = union(enum) {
37 inst: Mir.Inst.Index,
38 linker_extern_fn: Mir.Reloc,
39 linker_got: Mir.Reloc,
40 linker_direct: Mir.Reloc,
41 linker_import: Mir.Reloc,
42 linker_tlv: Mir.Reloc,
43 };
44};
2945
46/// The returned slice is overwritten by the next call to lowerMir.
47pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
48 insts: []const Instruction,
49 relocs: []const Reloc,
50} {
51 lower.result_insts = undefined;
52 lower.result_relocs = undefined;
53 errdefer lower.result_insts = undefined;
54 errdefer lower.result_relocs = undefined;
55 lower.result_insts_len = 0;
56 lower.result_relocs_len = 0;
57 defer lower.result_insts_len = undefined;
58 defer lower.result_relocs_len = undefined;
59
60 const inst = lower.mir.instructions.get(index);
3061 switch (inst.tag) {
31 .adc,
32 .add,
33 .@"and",
34 .bsf,
35 .bsr,
36 .bswap,
37 .bt,
38 .btc,
39 .btr,
40 .bts,
41 .call,
42 .cbw,
43 .cwde,
44 .cdqe,
45 .cwd,
46 .cdq,
47 .cqo,
48 .cmp,
49 .cmpxchg,
50 .div,
51 .fisttp,
52 .fld,
53 .idiv,
54 .imul,
55 .int3,
56 .jmp,
57 .lea,
58 .lfence,
59 .lzcnt,
60 .mfence,
61 .mov,
62 .movbe,
63 .movd,
64 .movq,
65 .movzx,
66 .mul,
67 .neg,
68 .nop,
69 .not,
70 .@"or",
71 .pop,
72 .popcnt,
73 .push,
74 .rcl,
75 .rcr,
76 .ret,
77 .rol,
78 .ror,
79 .sal,
80 .sar,
81 .sbb,
82 .sfence,
83 .shl,
84 .shld,
85 .shr,
86 .shrd,
87 .sub,
88 .syscall,
89 .@"test",
90 .tzcnt,
91 .ud2,
92 .xadd,
93 .xchg,
94 .xor,
95
96 .addss,
97 .andnps,
98 .andps,
99 .cmpss,
100 .cvtsi2ss,
101 .divss,
102 .maxss,
103 .minss,
104 .movaps,
105 .movss,
106 .movups,
107 .mulss,
108 .orps,
109 .pextrw,
110 .pinsrw,
111 .roundss,
112 .sqrtps,
113 .sqrtss,
114 .subss,
115 .ucomiss,
116 .xorps,
117 .addsd,
118 .andnpd,
119 .andpd,
120 .cmpsd,
121 .cvtsd2ss,
122 .cvtsi2sd,
123 .cvtss2sd,
124 .divsd,
125 .maxsd,
126 .minsd,
127 .movsd,
128 .mulsd,
129 .orpd,
130 .roundsd,
131 .sqrtpd,
132 .sqrtsd,
133 .subsd,
134 .ucomisd,
135 .xorpd,
136 => try lower.mirGeneric(inst),
137
138 .cmps,
139 .lods,
140 .movs,
141 .scas,
142 .stos,
143 => try lower.mirString(inst),
144
145 .cmpxchgb => try lower.mirCmpxchgBytes(inst),
146
147 .jmp_reloc => try lower.emit(.none, .jmp, &.{.{ .imm = Immediate.s(0) }}),
148
149 .call_extern => try lower.emit(.none, .call, &.{.{ .imm = Immediate.s(0) }}),
150
151 .lea_linker => try lower.mirLeaLinker(inst),
152 .mov_linker => try lower.mirMovLinker(inst),
153
154 .mov_moffs => try lower.mirMovMoffs(inst),
155
156 .movsx => try lower.mirMovsx(inst),
157 .cmovcc => try lower.mirCmovcc(inst),
158 .setcc => try lower.mirSetcc(inst),
159 .jcc => try lower.emit(.none, mnem_cc(.j, inst.data.inst_cc.cc), &.{.{ .imm = Immediate.s(0) }}),
62 else => try lower.generic(inst),
63 .pseudo => switch (inst.ops) {
64 .pseudo_cmov_z_and_np_rr => {
65 try lower.emit(.none, .cmovnz, &.{
66 .{ .reg = inst.data.rr.r2 },
67 .{ .reg = inst.data.rr.r1 },
68 });
69 try lower.emit(.none, .cmovnp, &.{
70 .{ .reg = inst.data.rr.r1 },
71 .{ .reg = inst.data.rr.r2 },
72 });
73 },
74 .pseudo_cmov_nz_or_p_rr => {
75 try lower.emit(.none, .cmovnz, &.{
76 .{ .reg = inst.data.rr.r1 },
77 .{ .reg = inst.data.rr.r2 },
78 });
79 try lower.emit(.none, .cmovp, &.{
80 .{ .reg = inst.data.rr.r1 },
81 .{ .reg = inst.data.rr.r2 },
82 });
83 },
84 .pseudo_cmov_nz_or_p_rm_sib,
85 .pseudo_cmov_nz_or_p_rm_rip,
86 => {
87 try lower.emit(.none, .cmovnz, &.{
88 .{ .reg = inst.data.rx.r1 },
89 .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
90 });
91 try lower.emit(.none, .cmovp, &.{
92 .{ .reg = inst.data.rx.r1 },
93 .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
94 });
95 },
96 .pseudo_set_z_and_np_r => {
97 try lower.emit(.none, .setz, &.{
98 .{ .reg = inst.data.r_scratch.r1 },
99 });
100 try lower.emit(.none, .setnp, &.{
101 .{ .reg = inst.data.r_scratch.scratch_reg },
102 });
103 try lower.emit(.none, .@"and", &.{
104 .{ .reg = inst.data.r_scratch.r1 },
105 .{ .reg = inst.data.r_scratch.scratch_reg },
106 });
107 },
108 .pseudo_set_z_and_np_m_sib,
109 .pseudo_set_z_and_np_m_rip,
110 => {
111 try lower.emit(.none, .setz, &.{
112 .{ .mem = lower.mem(inst.ops, inst.data.x_scratch.payload) },
113 });
114 try lower.emit(.none, .setnp, &.{
115 .{ .reg = inst.data.x_scratch.scratch_reg },
116 });
117 try lower.emit(.none, .@"and", &.{
118 .{ .mem = lower.mem(inst.ops, inst.data.x_scratch.payload) },
119 .{ .reg = inst.data.x_scratch.scratch_reg },
120 });
121 },
122 .pseudo_set_nz_or_p_r => {
123 try lower.emit(.none, .setnz, &.{
124 .{ .reg = inst.data.r_scratch.r1 },
125 });
126 try lower.emit(.none, .setp, &.{
127 .{ .reg = inst.data.r_scratch.scratch_reg },
128 });
129 try lower.emit(.none, .@"or", &.{
130 .{ .reg = inst.data.r_scratch.r1 },
131 .{ .reg = inst.data.r_scratch.scratch_reg },
132 });
133 },
134 .pseudo_set_nz_or_p_m_sib,
135 .pseudo_set_nz_or_p_m_rip,
136 => {
137 try lower.emit(.none, .setnz, &.{
138 .{ .mem = lower.mem(inst.ops, inst.data.x_scratch.payload) },
139 });
140 try lower.emit(.none, .setp, &.{
141 .{ .reg = inst.data.x_scratch.scratch_reg },
142 });
143 try lower.emit(.none, .@"or", &.{
144 .{ .mem = lower.mem(inst.ops, inst.data.x_scratch.payload) },
145 .{ .reg = inst.data.x_scratch.scratch_reg },
146 });
147 },
148 .pseudo_j_z_and_np_inst => {
149 try lower.emit(.none, .jnz, &.{
150 .{ .imm = lower.reloc(.{ .inst = index + 1 }) },
151 });
152 try lower.emit(.none, .jnp, &.{
153 .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) },
154 });
155 },
156 .pseudo_j_nz_or_p_inst => {
157 try lower.emit(.none, .jnz, &.{
158 .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) },
159 });
160 try lower.emit(.none, .jp, &.{
161 .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) },
162 });
163 },
160164
161 .push_regs => try lower.mirPushPopRegisterList(inst, .push),
162 .pop_regs => try lower.mirPushPopRegisterList(inst, .pop),
165 .pseudo_push_reg_list => try lower.pushPopRegList(.push, inst),
166 .pseudo_pop_reg_list => try lower.pushPopRegList(.pop, inst),
163167
164 .dbg_line,
165 .dbg_prologue_end,
166 .dbg_epilogue_begin,
167 .dead,
168 => {},
168 .pseudo_dbg_prologue_end_none,
169 .pseudo_dbg_line_line_column,
170 .pseudo_dbg_epilogue_begin_none,
171 .pseudo_dead_none,
172 => {},
173 else => unreachable,
174 },
169175 }
170176
171 return lower.result[0..lower.result_len];
177 return .{
178 .insts = lower.result_insts[0..lower.result_insts_len],
179 .relocs = lower.result_relocs[0..lower.result_relocs_len],
180 };
172181}
173182
174183pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error {
......@@ -178,12 +187,6 @@ pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error {
178187 return error.LowerFail;
179188}
180189
181fn mnem_cc(comptime base: @Type(.EnumLiteral), cc: bits.Condition) Mnemonic {
182 return switch (cc) {
183 inline else => |c| @field(Mnemonic, @tagName(base) ++ @tagName(c)),
184 };
185}
186
187190fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
188191 return switch (ops) {
189192 .rri_s,
......@@ -191,21 +194,22 @@ fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
191194 .i_s,
192195 .mi_sib_s,
193196 .mi_rip_s,
194 .lock_mi_sib_s,
195 .lock_mi_rip_s,
196197 => Immediate.s(@bitCast(i32, i)),
197198
199 .rrri,
198200 .rri_u,
199201 .ri_u,
200202 .i_u,
201203 .mi_sib_u,
202204 .mi_rip_u,
203 .lock_mi_sib_u,
204 .lock_mi_rip_u,
205205 .rmi_sib,
206206 .rmi_rip,
207207 .mri_sib,
208208 .mri_rip,
209 .rrm_sib,
210 .rrm_rip,
211 .rrmi_sib,
212 .rrmi_rip,
209213 => Immediate.u(i),
210214
211215 .ri64 => Immediate.u(lower.mir.extraData(Mir.Imm64, i).data.decode()),
......@@ -217,76 +221,108 @@ fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
217221fn mem(lower: Lower, ops: Mir.Inst.Ops, payload: u32) Memory {
218222 return lower.mir.resolveFrameLoc(switch (ops) {
219223 .rm_sib,
220 .rm_sib_cc,
221224 .rmi_sib,
222225 .m_sib,
223 .m_sib_cc,
224226 .mi_sib_u,
225227 .mi_sib_s,
226228 .mr_sib,
227229 .mrr_sib,
228230 .mri_sib,
229 .lock_m_sib,
230 .lock_mi_sib_u,
231 .lock_mi_sib_s,
232 .lock_mr_sib,
231 .rrm_sib,
232 .rrmi_sib,
233
234 .pseudo_cmov_nz_or_p_rm_sib,
235 .pseudo_set_z_and_np_m_sib,
236 .pseudo_set_nz_or_p_m_sib,
233237 => lower.mir.extraData(Mir.MemorySib, payload).data.decode(),
234238
235239 .rm_rip,
236 .rm_rip_cc,
237240 .rmi_rip,
238241 .m_rip,
239 .m_rip_cc,
240242 .mi_rip_u,
241243 .mi_rip_s,
242244 .mr_rip,
243245 .mrr_rip,
244246 .mri_rip,
245 .lock_m_rip,
246 .lock_mi_rip_u,
247 .lock_mi_rip_s,
248 .lock_mr_rip,
247 .rrm_rip,
248 .rrmi_rip,
249
250 .pseudo_cmov_nz_or_p_rm_rip,
251 .pseudo_set_z_and_np_m_rip,
252 .pseudo_set_nz_or_p_m_rip,
249253 => lower.mir.extraData(Mir.MemoryRip, payload).data.decode(),
250254
251255 .rax_moffs,
252256 .moffs_rax,
253 .lock_moffs_rax,
254257 => lower.mir.extraData(Mir.MemoryMoffs, payload).data.decode(),
255258
256259 else => unreachable,
257260 });
258261}
259262
263fn reloc(lower: *Lower, target: Reloc.Target) Immediate {
264 lower.result_relocs[lower.result_relocs_len] = .{
265 .lowered_inst_index = lower.result_insts_len,
266 .target = target,
267 };
268 lower.result_relocs_len += 1;
269 return Immediate.s(0);
270}
271
260272fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void {
261 lower.result[lower.result_len] = try Instruction.new(prefix, mnemonic, ops);
262 lower.result_len += 1;
273 lower.result_insts[lower.result_insts_len] = try Instruction.new(prefix, mnemonic, ops);
274 lower.result_insts_len += 1;
263275}
264276
265fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {
266 try lower.emit(switch (inst.ops) {
267 else => .none,
268 .lock_m_sib,
269 .lock_m_rip,
270 .lock_mi_sib_u,
271 .lock_mi_rip_u,
272 .lock_mi_sib_s,
273 .lock_mi_rip_s,
274 .lock_mr_sib,
275 .lock_mr_rip,
276 .lock_moffs_rax,
277 => .lock,
278 }, switch (inst.tag) {
279 inline else => |tag| if (@hasField(Mnemonic, @tagName(tag)))
280 @field(Mnemonic, @tagName(tag))
277fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
278 const fixes = switch (inst.ops) {
279 .none => inst.data.none.fixes,
280 .inst => inst.data.inst.fixes,
281 .i_s, .i_u => inst.data.i.fixes,
282 .r => inst.data.r.fixes,
283 .rr => inst.data.rr.fixes,
284 .rrr => inst.data.rrr.fixes,
285 .rrri => inst.data.rrri.fixes,
286 .rri_s, .rri_u => inst.data.rri.fixes,
287 .ri_s, .ri_u => inst.data.ri.fixes,
288 .ri64, .rm_sib, .rm_rip, .mr_sib, .mr_rip => inst.data.rx.fixes,
289 .mrr_sib, .mrr_rip, .rrm_sib, .rrm_rip => inst.data.rrx.fixes,
290 .rmi_sib, .rmi_rip, .mri_sib, .mri_rip => inst.data.rix.fixes,
291 .rrmi_sib, .rrmi_rip => inst.data.rrix.fixes,
292 .mi_sib_u, .mi_rip_u, .mi_sib_s, .mi_rip_s => inst.data.x.fixes,
293 .m_sib, .m_rip, .rax_moffs, .moffs_rax => inst.data.x.fixes,
294 .extern_fn_reloc, .got_reloc, .direct_reloc, .import_reloc, .tlv_reloc => ._,
295 else => return lower.fail("TODO lower .{s}", .{@tagName(inst.ops)}),
296 };
297 try lower.emit(switch (fixes) {
298 inline else => |tag| comptime if (std.mem.indexOfScalar(u8, @tagName(tag), ' ')) |space|
299 @field(Prefix, @tagName(tag)[0..space])
281300 else
282 unreachable,
301 .none,
302 }, mnemonic: {
303 comptime var max_len = 0;
304 inline for (@typeInfo(Mnemonic).Enum.fields) |field| max_len = @max(field.name.len, max_len);
305 var buf: [max_len]u8 = undefined;
306
307 const fixes_name = @tagName(fixes);
308 const pattern = fixes_name[if (std.mem.indexOfScalar(u8, fixes_name, ' ')) |i| i + 1 else 0..];
309 const wildcard_i = std.mem.indexOfScalar(u8, pattern, '_').?;
310 const parts = .{ pattern[0..wildcard_i], @tagName(inst.tag), pattern[wildcard_i + 1 ..] };
311 const err_msg = "unsupported mnemonic: ";
312 const mnemonic = std.fmt.bufPrint(&buf, "{s}{s}{s}", parts) catch
313 return lower.fail(err_msg ++ "'{s}{s}{s}'", parts);
314 break :mnemonic std.meta.stringToEnum(Mnemonic, mnemonic) orelse
315 return lower.fail(err_msg ++ "'{s}'", .{mnemonic});
283316 }, switch (inst.ops) {
284317 .none => &.{},
318 .inst => &.{
319 .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) },
320 },
285321 .i_s, .i_u => &.{
286 .{ .imm = lower.imm(inst.ops, inst.data.i) },
322 .{ .imm = lower.imm(inst.ops, inst.data.i.i) },
287323 },
288324 .r => &.{
289 .{ .reg = inst.data.r },
325 .{ .reg = inst.data.r.r1 },
290326 },
291327 .rr => &.{
292328 .{ .reg = inst.data.rr.r1 },
......@@ -297,12 +333,18 @@ fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {
297333 .{ .reg = inst.data.rrr.r2 },
298334 .{ .reg = inst.data.rrr.r3 },
299335 },
336 .rrri => &.{
337 .{ .reg = inst.data.rrri.r1 },
338 .{ .reg = inst.data.rrri.r2 },
339 .{ .reg = inst.data.rrri.r3 },
340 .{ .imm = lower.imm(inst.ops, inst.data.rrri.i) },
341 },
300342 .ri_s, .ri_u => &.{
301 .{ .reg = inst.data.ri.r },
343 .{ .reg = inst.data.ri.r1 },
302344 .{ .imm = lower.imm(inst.ops, inst.data.ri.i) },
303345 },
304346 .ri64 => &.{
305 .{ .reg = inst.data.rx.r },
347 .{ .reg = inst.data.rx.r1 },
306348 .{ .imm = lower.imm(inst.ops, inst.data.rx.payload) },
307349 },
308350 .rri_s, .rri_u => &.{
......@@ -310,33 +352,28 @@ fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {
310352 .{ .reg = inst.data.rri.r2 },
311353 .{ .imm = lower.imm(inst.ops, inst.data.rri.i) },
312354 },
313 .m_sib, .lock_m_sib, .m_rip, .lock_m_rip => &.{
314 .{ .mem = lower.mem(inst.ops, inst.data.payload) },
355 .m_sib, .m_rip => &.{
356 .{ .mem = lower.mem(inst.ops, inst.data.x.payload) },
315357 },
316 .mi_sib_s,
317 .lock_mi_sib_s,
318 .mi_sib_u,
319 .lock_mi_sib_u,
320 .mi_rip_u,
321 .lock_mi_rip_u,
322 .mi_rip_s,
323 .lock_mi_rip_s,
324 => &.{
325 .{ .mem = lower.mem(inst.ops, inst.data.ix.payload) },
326 .{ .imm = lower.imm(inst.ops, inst.data.ix.i) },
358 .mi_sib_s, .mi_sib_u, .mi_rip_u, .mi_rip_s => &.{
359 .{ .mem = lower.mem(inst.ops, inst.data.x.payload + 1) },
360 .{ .imm = lower.imm(
361 inst.ops,
362 lower.mir.extraData(Mir.Imm32, inst.data.x.payload).data.imm,
363 ) },
327364 },
328365 .rm_sib, .rm_rip => &.{
329 .{ .reg = inst.data.rx.r },
366 .{ .reg = inst.data.rx.r1 },
330367 .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
331368 },
332369 .rmi_sib, .rmi_rip => &.{
333 .{ .reg = inst.data.rix.r },
370 .{ .reg = inst.data.rix.r1 },
334371 .{ .mem = lower.mem(inst.ops, inst.data.rix.payload) },
335372 .{ .imm = lower.imm(inst.ops, inst.data.rix.i) },
336373 },
337 .mr_sib, .lock_mr_sib, .mr_rip, .lock_mr_rip => &.{
374 .mr_sib, .mr_rip => &.{
338375 .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
339 .{ .reg = inst.data.rx.r },
376 .{ .reg = inst.data.rx.r1 },
340377 },
341378 .mrr_sib, .mrr_rip => &.{
342379 .{ .mem = lower.mem(inst.ops, inst.data.rrx.payload) },
......@@ -345,137 +382,60 @@ fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {
345382 },
346383 .mri_sib, .mri_rip => &.{
347384 .{ .mem = lower.mem(inst.ops, inst.data.rix.payload) },
348 .{ .reg = inst.data.rix.r },
385 .{ .reg = inst.data.rix.r1 },
349386 .{ .imm = lower.imm(inst.ops, inst.data.rix.i) },
350387 },
351 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
352 });
353}
354
355fn mirString(lower: *Lower, inst: Mir.Inst) Error!void {
356 switch (inst.ops) {
357 .string => try lower.emit(switch (inst.data.string.repeat) {
358 inline else => |repeat| @field(Prefix, @tagName(repeat)),
359 }, switch (inst.tag) {
360 inline .cmps, .lods, .movs, .scas, .stos => |tag| switch (inst.data.string.width) {
361 inline else => |width| @field(Mnemonic, @tagName(tag) ++ @tagName(width)),
362 },
363 else => unreachable,
364 }, &.{}),
365 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
366 }
367}
368
369fn mirCmpxchgBytes(lower: *Lower, inst: Mir.Inst) Error!void {
370 const ops: [1]Operand = switch (inst.ops) {
371 .m_sib, .lock_m_sib, .m_rip, .lock_m_rip => .{
372 .{ .mem = lower.mem(inst.ops, inst.data.payload) },
388 .rrm_sib, .rrm_rip => &.{
389 .{ .reg = inst.data.rrx.r1 },
390 .{ .reg = inst.data.rrx.r2 },
391 .{ .mem = lower.mem(inst.ops, inst.data.rrx.payload) },
392 },
393 .rrmi_sib, .rrmi_rip => &.{
394 .{ .reg = inst.data.rrix.r1 },
395 .{ .reg = inst.data.rrix.r2 },
396 .{ .mem = lower.mem(inst.ops, inst.data.rrix.payload) },
397 .{ .imm = lower.imm(inst.ops, inst.data.rrix.i) },
373398 },
374 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
375 };
376 try lower.emit(switch (inst.ops) {
377 .m_sib, .m_rip => .none,
378 .lock_m_sib, .lock_m_rip => .lock,
379 else => unreachable,
380 }, switch (@divExact(ops[0].bitSize(), 8)) {
381 8 => .cmpxchg8b,
382 16 => .cmpxchg16b,
383 else => return lower.fail("invalid operand for {s}", .{@tagName(inst.tag)}),
384 }, &ops);
385}
386
387fn mirMovMoffs(lower: *Lower, inst: Mir.Inst) Error!void {
388 try lower.emit(switch (inst.ops) {
389 .rax_moffs, .moffs_rax => .none,
390 .lock_moffs_rax => .lock,
391 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
392 }, .mov, switch (inst.ops) {
393399 .rax_moffs => &.{
394400 .{ .reg = .rax },
395 .{ .mem = lower.mem(inst.ops, inst.data.payload) },
401 .{ .mem = lower.mem(inst.ops, inst.data.x.payload) },
396402 },
397 .moffs_rax, .lock_moffs_rax => &.{
398 .{ .mem = lower.mem(inst.ops, inst.data.payload) },
403 .moffs_rax => &.{
404 .{ .mem = lower.mem(inst.ops, inst.data.x.payload) },
399405 .{ .reg = .rax },
400406 },
401 else => unreachable,
402 });
403}
404
405fn mirMovsx(lower: *Lower, inst: Mir.Inst) Error!void {
406 const ops: [2]Operand = switch (inst.ops) {
407 .rr => .{
408 .{ .reg = inst.data.rr.r1 },
409 .{ .reg = inst.data.rr.r2 },
410 },
411 .rm_sib, .rm_rip => .{
412 .{ .reg = inst.data.rx.r },
413 .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
407 .extern_fn_reloc => &.{
408 .{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc }) },
414409 },
415 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
416 };
417 try lower.emit(.none, switch (ops[0].bitSize()) {
418 32, 64 => switch (ops[1].bitSize()) {
419 32 => .movsxd,
420 else => .movsx,
410 .got_reloc, .direct_reloc, .import_reloc, .tlv_reloc => ops: {
411 const reg = inst.data.rx.r1;
412 const extra = lower.mir.extraData(Mir.Reloc, inst.data.rx.payload).data;
413 _ = lower.reloc(switch (inst.ops) {
414 .got_reloc => .{ .linker_got = extra },
415 .direct_reloc => .{ .linker_direct = extra },
416 .import_reloc => .{ .linker_import = extra },
417 .tlv_reloc => .{ .linker_tlv = extra },
418 else => unreachable,
419 });
420 break :ops &.{
421 .{ .reg = reg },
422 .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) },
423 };
421424 },
422 else => .movsx,
423 }, &ops);
424}
425
426fn mirCmovcc(lower: *Lower, inst: Mir.Inst) Error!void {
427 switch (inst.ops) {
428 .rr_cc => try lower.emit(.none, mnem_cc(.cmov, inst.data.rr_cc.cc), &.{
429 .{ .reg = inst.data.rr_cc.r1 },
430 .{ .reg = inst.data.rr_cc.r2 },
431 }),
432 .rm_sib_cc, .rm_rip_cc => try lower.emit(.none, mnem_cc(.cmov, inst.data.rx_cc.cc), &.{
433 .{ .reg = inst.data.rx_cc.r },
434 .{ .mem = lower.mem(inst.ops, inst.data.rx_cc.payload) },
435 }),
436425 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
437 }
438}
439
440fn mirSetcc(lower: *Lower, inst: Mir.Inst) Error!void {
441 switch (inst.ops) {
442 .r_cc => try lower.emit(.none, mnem_cc(.set, inst.data.r_cc.cc), &.{
443 .{ .reg = inst.data.r_cc.r },
444 }),
445 .m_sib_cc, .m_rip_cc => try lower.emit(.none, mnem_cc(.set, inst.data.x_cc.cc), &.{
446 .{ .mem = lower.mem(inst.ops, inst.data.x_cc.payload) },
447 }),
448 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
449 }
426 });
450427}
451428
452fn mirPushPopRegisterList(lower: *Lower, inst: Mir.Inst, comptime mnemonic: Mnemonic) Error!void {
453 const reg_list = Mir.RegisterList.fromInt(inst.data.payload);
429fn pushPopRegList(lower: *Lower, comptime mnemonic: Mnemonic, inst: Mir.Inst) Error!void {
454430 const callee_preserved_regs = abi.getCalleePreservedRegs(lower.target.*);
455 var it = reg_list.iterator(.{ .direction = switch (mnemonic) {
431 var it = inst.data.reg_list.iterator(.{ .direction = switch (mnemonic) {
456432 .push => .reverse,
457433 .pop => .forward,
458434 else => unreachable,
459435 } });
460 while (it.next()) |i| try lower.emit(.none, mnemonic, &.{.{ .reg = callee_preserved_regs[i] }});
461}
462
463fn mirLeaLinker(lower: *Lower, inst: Mir.Inst) Error!void {
464 const metadata = lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data;
465 const reg = @intToEnum(Register, metadata.reg);
466 try lower.emit(.none, .lea, &.{
467 .{ .reg = reg },
468 .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) },
469 });
470}
471
472fn mirMovLinker(lower: *Lower, inst: Mir.Inst) Error!void {
473 const metadata = lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data;
474 const reg = @intToEnum(Register, metadata.reg);
475 try lower.emit(.none, .mov, &.{
476 .{ .reg = reg },
477 .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) },
478 });
436 while (it.next()) |i| try lower.emit(.none, mnemonic, &.{.{
437 .reg = callee_preserved_regs[i],
438 }});
479439}
480440
481441const abi = @import("abi.zig");
src/arch/x86_64/Mir.zig+560-276
......@@ -32,12 +32,260 @@ pub const Inst = struct {
3232
3333 pub const Index = u32;
3434
35 pub const Fixes = enum(u8) {
36 /// ___
37 @"_",
38
39 /// Integer __
40 i_,
41
42 /// ___ Left
43 _l,
44 /// ___ Left Double
45 _ld,
46 /// ___ Right
47 _r,
48 /// ___ Right Double
49 _rd,
50
51 /// ___ Above
52 _a,
53 /// ___ Above Or Equal
54 _ae,
55 /// ___ Below
56 _b,
57 /// ___ Below Or Equal
58 _be,
59 /// ___ Carry
60 _c,
61 /// ___ Equal
62 _e,
63 /// ___ Greater
64 _g,
65 /// ___ Greater Or Equal
66 _ge,
67 /// ___ Less
68 //_l,
69 /// ___ Less Or Equal
70 _le,
71 /// ___ Not Above
72 _na,
73 /// ___ Not Above Or Equal
74 _nae,
75 /// ___ Not Below
76 _nb,
77 /// ___ Not Below Or Equal
78 _nbe,
79 /// ___ Not Carry
80 _nc,
81 /// ___ Not Equal
82 _ne,
83 /// ___ Not Greater
84 _ng,
85 /// ___ Not Greater Or Equal
86 _nge,
87 /// ___ Not Less
88 _nl,
89 /// ___ Not Less Or Equal
90 _nle,
91 /// ___ Not Overflow
92 _no,
93 /// ___ Not Parity
94 _np,
95 /// ___ Not Sign
96 _ns,
97 /// ___ Not Zero
98 _nz,
99 /// ___ Overflow
100 _o,
101 /// ___ Parity
102 _p,
103 /// ___ Parity Even
104 _pe,
105 /// ___ Parity Odd
106 _po,
107 /// ___ Sign
108 _s,
109 /// ___ Zero
110 _z,
111
112 /// ___ Byte
113 //_b,
114 /// ___ Word
115 _w,
116 /// ___ Doubleword
117 _d,
118 /// ___ QuadWord
119 _q,
120
121 /// ___ String
122 //_s,
123 /// ___ String Byte
124 _sb,
125 /// ___ String Word
126 _sw,
127 /// ___ String Doubleword
128 _sd,
129 /// ___ String Quadword
130 _sq,
131
132 /// Repeat ___ String
133 @"rep _s",
134 /// Repeat ___ String Byte
135 @"rep _sb",
136 /// Repeat ___ String Word
137 @"rep _sw",
138 /// Repeat ___ String Doubleword
139 @"rep _sd",
140 /// Repeat ___ String Quadword
141 @"rep _sq",
142
143 /// Repeat Equal ___ String
144 @"repe _s",
145 /// Repeat Equal ___ String Byte
146 @"repe _sb",
147 /// Repeat Equal ___ String Word
148 @"repe _sw",
149 /// Repeat Equal ___ String Doubleword
150 @"repe _sd",
151 /// Repeat Equal ___ String Quadword
152 @"repe _sq",
153
154 /// Repeat Not Equal ___ String
155 @"repne _s",
156 /// Repeat Not Equal ___ String Byte
157 @"repne _sb",
158 /// Repeat Not Equal ___ String Word
159 @"repne _sw",
160 /// Repeat Not Equal ___ String Doubleword
161 @"repne _sd",
162 /// Repeat Not Equal ___ String Quadword
163 @"repne _sq",
164
165 /// Repeat Not Zero ___ String
166 @"repnz _s",
167 /// Repeat Not Zero ___ String Byte
168 @"repnz _sb",
169 /// Repeat Not Zero ___ String Word
170 @"repnz _sw",
171 /// Repeat Not Zero ___ String Doubleword
172 @"repnz _sd",
173 /// Repeat Not Zero ___ String Quadword
174 @"repnz _sq",
175
176 /// Repeat Zero ___ String
177 @"repz _s",
178 /// Repeat Zero ___ String Byte
179 @"repz _sb",
180 /// Repeat Zero ___ String Word
181 @"repz _sw",
182 /// Repeat Zero ___ String Doubleword
183 @"repz _sd",
184 /// Repeat Zero ___ String Quadword
185 @"repz _sq",
186
187 /// Locked ___
188 @"lock _",
189 /// ___ And Complement
190 //_c,
191 /// Locked ___ And Complement
192 @"lock _c",
193 /// ___ And Reset
194 //_r,
195 /// Locked ___ And Reset
196 @"lock _r",
197 /// ___ And Set
198 //_s,
199 /// Locked ___ And Set
200 @"lock _s",
201 /// ___ 8 Bytes
202 _8b,
203 /// Locked ___ 8 Bytes
204 @"lock _8b",
205 /// ___ 16 Bytes
206 _16b,
207 /// Locked ___ 16 Bytes
208 @"lock _16b",
209
210 /// Float ___
211 f_,
212 /// Float ___ Pop
213 f_p,
214
215 /// Packed ___
216 p_,
217 /// Packed ___ Byte
218 p_b,
219 /// Packed ___ Word
220 p_w,
221 /// Packed ___ Doubleword
222 p_d,
223 /// Packed ___ Quadword
224 p_q,
225 /// Packed ___ Double Quadword
226 p_dq,
227
228 /// ___ Scalar Single-Precision Values
229 _ss,
230 /// ___ Packed Single-Precision Values
231 _ps,
232 /// ___ Scalar Double-Precision Values
233 //_sd,
234 /// ___ Packed Double-Precision Values
235 _pd,
236
237 /// VEX-Encoded ___
238 v_,
239 /// VEX-Encoded Packed ___
240 vp_,
241 /// VEX-Encoded Packed ___ Byte
242 vp_b,
243 /// VEX-Encoded Packed ___ Word
244 vp_w,
245 /// VEX-Encoded Packed ___ Doubleword
246 vp_d,
247 /// VEX-Encoded Packed ___ Quadword
248 vp_q,
249 /// VEX-Encoded Packed ___ Double Quadword
250 vp_dq,
251 /// VEX-Encoded ___ Scalar Single-Precision Values
252 v_ss,
253 /// VEX-Encoded ___ Packed Single-Precision Values
254 v_ps,
255 /// VEX-Encoded ___ Scalar Double-Precision Values
256 v_sd,
257 /// VEX-Encoded ___ Packed Double-Precision Values
258 v_pd,
259
260 /// Mask ___ Byte
261 k_b,
262 /// Mask ___ Word
263 k_w,
264 /// Mask ___ Doubleword
265 k_d,
266 /// Mask ___ Quadword
267 k_q,
268
269 pub fn fromCondition(cc: bits.Condition) Fixes {
270 return switch (cc) {
271 inline else => |cc_tag| @field(Fixes, "_" ++ @tagName(cc_tag)),
272 .z_and_np, .nz_or_p => unreachable,
273 };
274 }
275 };
276
35277 pub const Tag = enum(u8) {
36278 /// Add with carry
37279 adc,
38280 /// Add
281 /// Add packed single-precision floating-point values
282 /// Add scalar single-precision floating-point values
283 /// Add packed double-precision floating-point values
284 /// Add scalar double-precision floating-point values
39285 add,
40286 /// Logical and
287 /// Bitwise logical and of packed single-precision floating-point values
288 /// Bitwise logical and of packed double-precision floating-point values
41289 @"and",
42290 /// Bit scan forward
43291 bsf,
......@@ -46,49 +294,55 @@ pub const Inst = struct {
46294 /// Byte swap
47295 bswap,
48296 /// Bit test
49 bt,
50297 /// Bit test and complement
51 btc,
52298 /// Bit test and reset
53 btr,
54299 /// Bit test and set
55 bts,
300 bt,
56301 /// Call
57302 call,
58303 /// Convert byte to word
59304 cbw,
60 /// Convert word to doubleword
61 cwde,
62 /// Convert doubleword to quadword
63 cdqe,
64 /// Convert word to doubleword
65 cwd,
66305 /// Convert doubleword to quadword
67306 cdq,
68307 /// Convert doubleword to quadword
69 cqo,
308 cdqe,
309 /// Conditional move
310 cmov,
70311 /// Logical compare
312 /// Compare string
313 /// Compare scalar single-precision floating-point values
314 /// Compare scalar double-precision floating-point values
71315 cmp,
72316 /// Compare and exchange
73 cmpxchg,
74317 /// Compare and exchange bytes
75 cmpxchgb,
318 cmpxchg,
319 /// Convert doubleword to quadword
320 cqo,
321 /// Convert word to doubleword
322 cwd,
323 /// Convert word to doubleword
324 cwde,
76325 /// Unsigned division
77 div,
78 /// Store integer with truncation
79 fisttp,
80 /// Load floating-point value
81 fld,
82326 /// Signed division
83 idiv,
84 /// Signed multiplication
85 imul,
327 /// Divide packed single-precision floating-point values
328 /// Divide scalar single-precision floating-point values
329 /// Divide packed double-precision floating-point values
330 /// Divide scalar double-precision floating-point values
331 div,
86332 ///
87333 int3,
334 /// Store integer with truncation
335 istt,
336 /// Conditional jump
337 j,
88338 /// Jump
89339 jmp,
340 /// Load floating-point value
341 ld,
90342 /// Load effective address
91343 lea,
344 /// Load string
345 lod,
92346 /// Load fence
93347 lfence,
94348 /// Count the number of leading zero bits
......@@ -96,18 +350,24 @@ pub const Inst = struct {
96350 /// Memory fence
97351 mfence,
98352 /// Move
353 /// Move data from string to string
354 /// Move scalar single-precision floating-point value
355 /// Move scalar double-precision floating-point value
356 /// Move doubleword
357 /// Move quadword
99358 mov,
100359 /// Move data after swapping bytes
101360 movbe,
102 /// Move doubleword
103 movd,
104 /// Move quadword
105 movq,
106361 /// Move with sign extension
107362 movsx,
108363 /// Move with zero extension
109364 movzx,
110365 /// Multiply
366 /// Signed multiplication
367 /// Multiply packed single-precision floating-point values
368 /// Multiply scalar single-precision floating-point values
369 /// Multiply packed double-precision floating-point values
370 /// Multiply scalar double-precision floating-point values
111371 mul,
112372 /// Two's complement negation
113373 neg,
......@@ -116,6 +376,8 @@ pub const Inst = struct {
116376 /// One's complement negation
117377 not,
118378 /// Logical or
379 /// Bitwise logical or of packed single-precision floating-point values
380 /// Bitwise logical or of packed double-precision floating-point values
119381 @"or",
120382 /// Pop
121383 pop,
......@@ -124,33 +386,37 @@ pub const Inst = struct {
124386 /// Push
125387 push,
126388 /// Rotate left through carry
127 rcl,
128389 /// Rotate right through carry
129 rcr,
390 rc,
130391 /// Return
131392 ret,
132393 /// Rotate left
133 rol,
134394 /// Rotate right
135 ror,
395 ro,
136396 /// Arithmetic shift left
137 sal,
138397 /// Arithmetic shift right
139 sar,
398 sa,
140399 /// Integer subtraction with borrow
141400 sbb,
401 /// Scan string
402 sca,
403 /// Set byte on condition
404 set,
142405 /// Store fence
143406 sfence,
144407 /// Logical shift left
145 shl,
146408 /// Double precision shift left
147 shld,
148409 /// Logical shift right
149 shr,
150410 /// Double precision shift right
151 shrd,
411 sh,
152412 /// Subtract
413 /// Subtract packed single-precision floating-point values
414 /// Subtract scalar single-precision floating-point values
415 /// Subtract packed double-precision floating-point values
416 /// Subtract scalar double-precision floating-point values
153417 sub,
418 /// Store string
419 sto,
154420 /// Syscall
155421 syscall,
156422 /// Test condition
......@@ -164,142 +430,131 @@ pub const Inst = struct {
164430 /// Exchange register/memory with register
165431 xchg,
166432 /// Logical exclusive-or
433 /// Bitwise logical xor of packed single-precision floating-point values
434 /// Bitwise logical xor of packed double-precision floating-point values
167435 xor,
168436
169 /// Add single precision floating point values
170 addss,
171 /// Bitwise logical and of packed single precision floating-point values
172 andps,
173 /// Bitwise logical and not of packed single precision floating-point values
174 andnps,
175 /// Compare scalar single-precision floating-point values
176 cmpss,
437 /// Bitwise logical and not of packed single-precision floating-point values
438 /// Bitwise logical and not of packed double-precision floating-point values
439 andn,
177440 /// Convert doubleword integer to scalar single-precision floating-point value
178441 cvtsi2ss,
179 /// Divide scalar single-precision floating-point values
180 divss,
181 /// Return maximum single-precision floating-point value
182 maxss,
183 /// Return minimum single-precision floating-point value
184 minss,
442 /// Maximum of packed single-precision floating-point values
443 /// Maximum of scalar single-precision floating-point values
444 /// Maximum of packed double-precision floating-point values
445 /// Maximum of scalar double-precision floating-point values
446 max,
447 /// Minimum of packed single-precision floating-point values
448 /// Minimum of scalar single-precision floating-point values
449 /// Minimum of packed double-precision floating-point values
450 /// Minimum of scalar double-precision floating-point values
451 min,
185452 /// Move aligned packed single-precision floating-point values
186 movaps,
187 /// Move scalar single-precision floating-point value
188 movss,
453 /// Move aligned packed double-precision floating-point values
454 mova,
455 /// Move packed single-precision floating-point values high to low
456 movhl,
189457 /// Move unaligned packed single-precision floating-point values
190 movups,
191 /// Multiply scalar single-precision floating-point values
192 mulss,
193 /// Bitwise logical or of packed single precision floating-point values
194 orps,
458 /// Move unaligned packed double-precision floating-point values
459 movu,
460 /// Extract byte
195461 /// Extract word
196 pextrw,
462 /// Extract doubleword
463 /// Extract quadword
464 extr,
465 /// Insert byte
197466 /// Insert word
198 pinsrw,
199 /// Round scalar single-precision floating-point values
200 roundss,
201 /// Square root of scalar single precision floating-point value
202 sqrtps,
203 /// Subtract scalar single-precision floating-point values
204 sqrtss,
205 /// Square root of single precision floating-point values
206 subss,
467 /// Insert doubleword
468 /// Insert quadword
469 insr,
470 /// Square root of packed single-precision floating-point values
471 /// Square root of scalar single-precision floating-point value
472 /// Square root of packed double-precision floating-point values
473 /// Square root of scalar double-precision floating-point value
474 sqrt,
207475 /// Unordered compare scalar single-precision floating-point values
208 ucomiss,
209 /// Bitwise logical xor of packed single precision floating-point values
210 xorps,
211 /// Add double precision floating point values
212 addsd,
213 /// Bitwise logical and not of packed double precision floating-point values
214 andnpd,
215 /// Bitwise logical and of packed double precision floating-point values
216 andpd,
217 /// Compare scalar double-precision floating-point values
218 cmpsd,
476 /// Unordered compare scalar double-precision floating-point values
477 ucomi,
478 /// Unpack and interleave high packed single-precision floating-point values
479 /// Unpack and interleave high packed double-precision floating-point values
480 unpckh,
481 /// Unpack and interleave low packed single-precision floating-point values
482 /// Unpack and interleave low packed double-precision floating-point values
483 unpckl,
484
219485 /// Convert scalar double-precision floating-point value to scalar single-precision floating-point value
220486 cvtsd2ss,
221487 /// Convert doubleword integer to scalar double-precision floating-point value
222488 cvtsi2sd,
223489 /// Convert scalar single-precision floating-point value to scalar double-precision floating-point value
224490 cvtss2sd,
225 /// Divide scalar double-precision floating-point values
226 divsd,
227 /// Return maximum double-precision floating-point value
228 maxsd,
229 /// Return minimum double-precision floating-point value
230 minsd,
231 /// Move scalar double-precision floating-point value
232 movsd,
233 /// Multiply scalar double-precision floating-point values
234 mulsd,
235 /// Bitwise logical or of packed double precision floating-point values
236 orpd,
237 /// Round scalar double-precision floating-point values
238 roundsd,
239 /// Square root of double precision floating-point values
240 sqrtpd,
241 /// Square root of scalar double precision floating-point value
242 sqrtsd,
243 /// Subtract scalar double-precision floating-point values
244 subsd,
245 /// Unordered compare scalar double-precision floating-point values
246 ucomisd,
247 /// Bitwise logical xor of packed double precision floating-point values
248 xorpd,
491 /// Shuffle packed high words
492 shufh,
493 /// Shuffle packed low words
494 shufl,
495 /// Shift packed data right logical
496 /// Shift packed data right logical
497 /// Shift packed data right logical
498 srl,
499 /// Unpack high data
500 unpckhbw,
501 /// Unpack high data
502 unpckhdq,
503 /// Unpack high data
504 unpckhqdq,
505 /// Unpack high data
506 unpckhwd,
507 /// Unpack low data
508 unpcklbw,
509 /// Unpack low data
510 unpckldq,
511 /// Unpack low data
512 unpcklqdq,
513 /// Unpack low data
514 unpcklwd,
249515
250 /// Compare string operands
251 cmps,
252 /// Load string
253 lods,
254 /// Move data from string to string
255 movs,
256 /// Scan string
257 scas,
258 /// Store string
259 stos,
260
261 /// Conditional move
262 cmovcc,
263 /// Conditional jump
264 jcc,
265 /// Set byte on condition
266 setcc,
267
268 /// Mov absolute to/from memory wrt segment register to/from rax
269 mov_moffs,
270
271 /// Jump with relocation to another local MIR instruction
272 /// Uses `inst` payload.
273 jmp_reloc,
516 /// Replicate double floating-point values
517 movddup,
518 /// Replicate single floating-point values
519 movshdup,
520 /// Replicate single floating-point values
521 movsldup,
274522
275 /// Call to an extern symbol via linker relocation.
276 /// Uses `relocation` payload.
277 call_extern,
523 /// Round packed single-precision floating-point values
524 /// Round scalar single-precision floating-point value
525 /// Round packed double-precision floating-point values
526 /// Round scalar double-precision floating-point value
527 round,
278528
279 /// Load effective address of a symbol not yet allocated in VM.
280 lea_linker,
281 /// Move address of a symbol not yet allocated in VM.
282 mov_linker,
529 /// Convert 16-bit floating-point values to single-precision floating-point values
530 cvtph2ps,
531 /// Convert single-precision floating-point values to 16-bit floating-point values
532 cvtps2ph,
283533
284 /// End of prologue
285 dbg_prologue_end,
286 /// Start of epilogue
287 dbg_epilogue_begin,
288 /// Update debug line
289 /// Uses `line_column` payload containing the line and column.
290 dbg_line,
291 /// Push registers
292 /// Uses `payload` payload containing `RegisterList.asInt` directly.
293 push_regs,
294 /// Pop registers
295 /// Uses `payload` payload containing `RegisterList.asInt` directly.
296 pop_regs,
534 /// Fused multiply-add of packed single-precision floating-point values
535 /// Fused multiply-add of scalar single-precision floating-point values
536 /// Fused multiply-add of packed double-precision floating-point values
537 /// Fused multiply-add of scalar double-precision floating-point values
538 fmadd132,
539 /// Fused multiply-add of packed single-precision floating-point values
540 /// Fused multiply-add of scalar single-precision floating-point values
541 /// Fused multiply-add of packed double-precision floating-point values
542 /// Fused multiply-add of scalar double-precision floating-point values
543 fmadd213,
544 /// Fused multiply-add of packed single-precision floating-point values
545 /// Fused multiply-add of scalar single-precision floating-point values
546 /// Fused multiply-add of packed double-precision floating-point values
547 /// Fused multiply-add of scalar double-precision floating-point values
548 fmadd231,
297549
298 /// Tombstone
299 /// Emitter should skip this instruction.
300 dead,
550 /// A pseudo instruction that requires special lowering.
551 /// This should be the only tag in this enum that doesn't
552 /// directly correspond to one or more instruction mnemonics.
553 pseudo,
301554 };
302555
556 pub const FixedTag = struct { Fixes, Tag };
557
303558 pub const Ops = enum(u8) {
304559 /// No data associated with this instruction (only mnemonic is used).
305560 none,
......@@ -312,18 +567,15 @@ pub const Inst = struct {
312567 /// Register, register, register operands.
313568 /// Uses `rrr` payload.
314569 rrr,
570 /// Register, register, register, immediate (byte) operands.
571 /// Uses `rrri` payload.
572 rrri,
315573 /// Register, register, immediate (sign-extended) operands.
316574 /// Uses `rri` payload.
317575 rri_s,
318576 /// Register, register, immediate (unsigned) operands.
319577 /// Uses `rri` payload.
320578 rri_u,
321 /// Register with condition code (CC).
322 /// Uses `r_cc` payload.
323 r_cc,
324 /// Register, register with condition code (CC).
325 /// Uses `rr_cc` payload.
326 rr_cc,
327579 /// Register, immediate (sign-extended) operands.
328580 /// Uses `ri` payload.
329581 ri_s,
......@@ -348,41 +600,41 @@ pub const Inst = struct {
348600 /// Register, memory (RIP) operands.
349601 /// Uses `rx` payload.
350602 rm_rip,
351 /// Register, memory (SIB) operands with condition code (CC).
352 /// Uses `rx_cc` payload.
353 rm_sib_cc,
354 /// Register, memory (RIP) operands with condition code (CC).
355 /// Uses `rx_cc` payload.
356 rm_rip_cc,
357603 /// Register, memory (SIB), immediate (byte) operands.
358604 /// Uses `rix` payload with extra data of type `MemorySib`.
359605 rmi_sib,
606 /// Register, register, memory (RIP).
607 /// Uses `rrix` payload with extra data of type `MemoryRip`.
608 rrm_rip,
609 /// Register, register, memory (SIB).
610 /// Uses `rrix` payload with extra data of type `MemorySib`.
611 rrm_sib,
612 /// Register, register, memory (RIP), immediate (byte) operands.
613 /// Uses `rrix` payload with extra data of type `MemoryRip`.
614 rrmi_rip,
615 /// Register, register, memory (SIB), immediate (byte) operands.
616 /// Uses `rrix` payload with extra data of type `MemorySib`.
617 rrmi_sib,
360618 /// Register, memory (RIP), immediate (byte) operands.
361619 /// Uses `rix` payload with extra data of type `MemoryRip`.
362620 rmi_rip,
363621 /// Single memory (SIB) operand.
364 /// Uses `payload` with extra data of type `MemorySib`.
622 /// Uses `x` with extra data of type `MemorySib`.
365623 m_sib,
366624 /// Single memory (RIP) operand.
367 /// Uses `payload` with extra data of type `MemoryRip`.
625 /// Uses `x` with extra data of type `MemoryRip`.
368626 m_rip,
369 /// Single memory (SIB) operand with condition code (CC).
370 /// Uses `x_cc` with extra data of type `MemorySib`.
371 m_sib_cc,
372 /// Single memory (RIP) operand with condition code (CC).
373 /// Uses `x_cc` with extra data of type `MemoryRip`.
374 m_rip_cc,
375627 /// Memory (SIB), immediate (unsigned) operands.
376 /// Uses `ix` payload with extra data of type `MemorySib`.
628 /// Uses `x` payload with extra data of type `Imm32` followed by `MemorySib`.
377629 mi_sib_u,
378630 /// Memory (RIP), immediate (unsigned) operands.
379 /// Uses `ix` payload with extra data of type `MemoryRip`.
631 /// Uses `x` payload with extra data of type `Imm32` followed by `MemoryRip`.
380632 mi_rip_u,
381633 /// Memory (SIB), immediate (sign-extend) operands.
382 /// Uses `ix` payload with extra data of type `MemorySib`.
634 /// Uses `x` payload with extra data of type `Imm32` followed by `MemorySib`.
383635 mi_sib_s,
384636 /// Memory (RIP), immediate (sign-extend) operands.
385 /// Uses `ix` payload with extra data of type `MemoryRip`.
637 /// Uses `x` payload with extra data of type `Imm32` followed by `MemoryRip`.
386638 mi_rip_s,
387639 /// Memory (SIB), register operands.
388640 /// Uses `rx` payload with extra data of type `MemorySib`.
......@@ -403,161 +655,200 @@ pub const Inst = struct {
403655 /// Uses `rix` payload with extra data of type `MemoryRip`.
404656 mri_rip,
405657 /// Rax, Memory moffs.
406 /// Uses `payload` with extra data of type `MemoryMoffs`.
658 /// Uses `x` with extra data of type `MemoryMoffs`.
407659 rax_moffs,
408660 /// Memory moffs, rax.
409 /// Uses `payload` with extra data of type `MemoryMoffs`.
661 /// Uses `x` with extra data of type `MemoryMoffs`.
410662 moffs_rax,
411 /// Single memory (SIB) operand with lock prefix.
412 /// Uses `payload` with extra data of type `MemorySib`.
413 lock_m_sib,
414 /// Single memory (RIP) operand with lock prefix.
415 /// Uses `payload` with extra data of type `MemoryRip`.
416 lock_m_rip,
417 /// Memory (SIB), immediate (unsigned) operands with lock prefix.
418 /// Uses `xi` payload with extra data of type `MemorySib`.
419 lock_mi_sib_u,
420 /// Memory (RIP), immediate (unsigned) operands with lock prefix.
421 /// Uses `xi` payload with extra data of type `MemoryRip`.
422 lock_mi_rip_u,
423 /// Memory (SIB), immediate (sign-extend) operands with lock prefix.
424 /// Uses `xi` payload with extra data of type `MemorySib`.
425 lock_mi_sib_s,
426 /// Memory (RIP), immediate (sign-extend) operands with lock prefix.
427 /// Uses `xi` payload with extra data of type `MemoryRip`.
428 lock_mi_rip_s,
429 /// Memory (SIB), register operands with lock prefix.
430 /// Uses `rx` payload with extra data of type `MemorySib`.
431 lock_mr_sib,
432 /// Memory (RIP), register operands with lock prefix.
433 /// Uses `rx` payload with extra data of type `MemoryRip`.
434 lock_mr_rip,
435 /// Memory moffs, rax with lock prefix.
436 /// Uses `payload` with extra data of type `MemoryMoffs`.
437 lock_moffs_rax,
438663 /// References another Mir instruction directly.
439664 /// Uses `inst` payload.
440665 inst,
441 /// References another Mir instruction directly with condition code (CC).
442 /// Uses `inst_cc` payload.
443 inst_cc,
444 /// String repeat and width
445 /// Uses `string` payload.
446 string,
666 /// Linker relocation - external function.
447667 /// Uses `reloc` payload.
448 reloc,
668 extern_fn_reloc,
449669 /// Linker relocation - GOT indirection.
450 /// Uses `payload` payload with extra data of type `LeaRegisterReloc`.
670 /// Uses `rx` payload with extra data of type `Reloc`.
451671 got_reloc,
452672 /// Linker relocation - direct reference.
453 /// Uses `payload` payload with extra data of type `LeaRegisterReloc`.
673 /// Uses `rx` payload with extra data of type `Reloc`.
454674 direct_reloc,
455675 /// Linker relocation - imports table indirection (binding).
456 /// Uses `payload` payload with extra data of type `LeaRegisterReloc`.
676 /// Uses `rx` payload with extra data of type `Reloc`.
457677 import_reloc,
458678 /// Linker relocation - threadlocal variable via GOT indirection.
459 /// Uses `payload` payload with extra data of type `LeaRegisterReloc`.
679 /// Uses `rx` payload with extra data of type `Reloc`.
460680 tlv_reloc,
681
682 // Pseudo instructions:
683
684 /// Conditional move if zero flag set and parity flag not set
685 /// Clobbers the source operand!
686 /// Uses `rr` payload.
687 pseudo_cmov_z_and_np_rr,
688 /// Conditional move if zero flag not set or parity flag set
689 /// Uses `rr` payload.
690 pseudo_cmov_nz_or_p_rr,
691 /// Conditional move if zero flag not set or parity flag set
692 /// Uses `rx` payload.
693 pseudo_cmov_nz_or_p_rm_sib,
694 /// Conditional move if zero flag not set or parity flag set
695 /// Uses `rx` payload.
696 pseudo_cmov_nz_or_p_rm_rip,
697 /// Set byte if zero flag set and parity flag not set
698 /// Requires a scratch register!
699 /// Uses `r_scratch` payload.
700 pseudo_set_z_and_np_r,
701 /// Set byte if zero flag set and parity flag not set
702 /// Requires a scratch register!
703 /// Uses `x_scratch` payload.
704 pseudo_set_z_and_np_m_sib,
705 /// Set byte if zero flag set and parity flag not set
706 /// Requires a scratch register!
707 /// Uses `x_scratch` payload.
708 pseudo_set_z_and_np_m_rip,
709 /// Set byte if zero flag not set or parity flag set
710 /// Requires a scratch register!
711 /// Uses `r_scratch` payload.
712 pseudo_set_nz_or_p_r,
713 /// Set byte if zero flag not set or parity flag set
714 /// Requires a scratch register!
715 /// Uses `x_scratch` payload.
716 pseudo_set_nz_or_p_m_sib,
717 /// Set byte if zero flag not set or parity flag set
718 /// Requires a scratch register!
719 /// Uses `x_scratch` payload.
720 pseudo_set_nz_or_p_m_rip,
721 /// Jump if zero flag set and parity flag not set
722 /// Uses `inst` payload.
723 pseudo_j_z_and_np_inst,
724 /// Jump if zero flag not set or parity flag set
725 /// Uses `inst` payload.
726 pseudo_j_nz_or_p_inst,
727
728 /// Push registers
729 /// Uses `reg_list` payload.
730 pseudo_push_reg_list,
731 /// Pop registers
732 /// Uses `reg_list` payload.
733 pseudo_pop_reg_list,
734
735 /// End of prologue
736 pseudo_dbg_prologue_end_none,
737 /// Update debug line
738 /// Uses `line_column` payload.
739 pseudo_dbg_line_line_column,
740 /// Start of epilogue
741 pseudo_dbg_epilogue_begin_none,
742
743 /// Tombstone
744 /// Emitter should skip this instruction.
745 pseudo_dead_none,
461746 };
462747
463748 pub const Data = union {
749 none: struct {
750 fixes: Fixes = ._,
751 },
464752 /// References another Mir instruction.
465 inst: Index,
466 /// Another instruction with condition code (CC).
467 /// Used by `jcc`.
468 inst_cc: struct {
469 /// Another instruction.
753 inst: struct {
754 fixes: Fixes = ._,
470755 inst: Index,
471 /// A condition code for use with EFLAGS register.
472 cc: bits.Condition,
473756 },
474757 /// A 32-bit immediate value.
475 i: u32,
476 r: Register,
758 i: struct {
759 fixes: Fixes = ._,
760 i: u32,
761 },
762 r: struct {
763 fixes: Fixes = ._,
764 r1: Register,
765 },
477766 rr: struct {
767 fixes: Fixes = ._,
478768 r1: Register,
479769 r2: Register,
480770 },
481771 rrr: struct {
772 fixes: Fixes = ._,
482773 r1: Register,
483774 r2: Register,
484775 r3: Register,
485776 },
486 rri: struct {
777 rrri: struct {
778 fixes: Fixes = ._,
487779 r1: Register,
488780 r2: Register,
489 i: u32,
490 },
491 /// Condition code (CC), followed by custom payload found in extra.
492 x_cc: struct {
493 cc: bits.Condition,
494 payload: u32,
495 },
496 /// Register with condition code (CC).
497 r_cc: struct {
498 r: Register,
499 cc: bits.Condition,
781 r3: Register,
782 i: u8,
500783 },
501 /// Register, register with condition code (CC).
502 rr_cc: struct {
784 rri: struct {
785 fixes: Fixes = ._,
503786 r1: Register,
504787 r2: Register,
505 cc: bits.Condition,
788 i: u32,
506789 },
507790 /// Register, immediate.
508791 ri: struct {
509 r: Register,
792 fixes: Fixes = ._,
793 r1: Register,
510794 i: u32,
511795 },
512796 /// Register, followed by custom payload found in extra.
513797 rx: struct {
514 r: Register,
515 payload: u32,
516 },
517 /// Register with condition code (CC), followed by custom payload found in extra.
518 rx_cc: struct {
519 r: Register,
520 cc: bits.Condition,
521 payload: u32,
522 },
523 /// Immediate, followed by Custom payload found in extra.
524 ix: struct {
525 i: u32,
798 fixes: Fixes = ._,
799 r1: Register,
526800 payload: u32,
527801 },
528802 /// Register, register, followed by Custom payload found in extra.
529803 rrx: struct {
804 fixes: Fixes = ._,
530805 r1: Register,
531806 r2: Register,
532807 payload: u32,
533808 },
534809 /// Register, byte immediate, followed by Custom payload found in extra.
535810 rix: struct {
536 r: Register,
811 fixes: Fixes = ._,
812 r1: Register,
813 i: u8,
814 payload: u32,
815 },
816 /// Register, register, byte immediate, followed by Custom payload found in extra.
817 rrix: struct {
818 fixes: Fixes = ._,
819 r1: Register,
820 r2: Register,
537821 i: u8,
538822 payload: u32,
539823 },
540 /// String instruction prefix and width.
541 string: struct {
542 repeat: bits.StringRepeat,
543 width: bits.StringWidth,
824 /// Register, scratch register
825 r_scratch: struct {
826 fixes: Fixes = ._,
827 r1: Register,
828 scratch_reg: Register,
829 },
830 /// Scratch register, followed by Custom payload found in extra.
831 x_scratch: struct {
832 fixes: Fixes = ._,
833 scratch_reg: Register,
834 payload: u32,
835 },
836 /// Custom payload found in extra.
837 x: struct {
838 fixes: Fixes = ._,
839 payload: u32,
544840 },
545841 /// Relocation for the linker where:
546842 /// * `atom_index` is the index of the source
547843 /// * `sym_index` is the index of the target
548 relocation: struct {
549 /// Index of the containing atom.
550 atom_index: u32,
551 /// Index into the linker's symbol table.
552 sym_index: u32,
553 },
844 reloc: Reloc,
554845 /// Debug line and column position
555846 line_column: struct {
556847 line: u32,
557848 column: u32,
558849 },
559 /// Index into `extra`. Meaning of what can be found there is context-dependent.
560 payload: u32,
850 /// Register list
851 reg_list: RegisterList,
561852 };
562853
563854 // Make sure we don't accidentally make instructions bigger than expected.
......@@ -569,9 +860,8 @@ pub const Inst = struct {
569860 }
570861};
571862
572pub const LeaRegisterReloc = struct {
573 /// Destination register.
574 reg: u32,
863/// A linker symbol not yet allocated in VM.
864pub const Reloc = struct {
575865 /// Index of the containing atom.
576866 atom_index: u32,
577867 /// Index into the linker's symbol table.
......@@ -606,21 +896,15 @@ pub const RegisterList = struct {
606896 return self.bitset.iterator(options);
607897 }
608898
609 pub fn asInt(self: Self) u32 {
610 return self.bitset.mask;
611 }
612
613 pub fn fromInt(mask: u32) Self {
614 return .{
615 .bitset = BitSet{ .mask = @intCast(BitSet.MaskInt, mask) },
616 };
617 }
618
619899 pub fn count(self: Self) u32 {
620900 return @intCast(u32, self.bitset.count());
621901 }
622902};
623903
904pub const Imm32 = struct {
905 imm: u32,
906};
907
624908pub const Imm64 = struct {
625909 msb: u32,
626910 lsb: u32,
src/arch/x86_64/bits.zig+21-7
......@@ -6,9 +6,6 @@ const Allocator = std.mem.Allocator;
66const ArrayList = std.ArrayList;
77const DW = std.dwarf;
88
9pub const StringRepeat = enum(u3) { none, rep, repe, repz, repne, repnz };
10pub const StringWidth = enum(u2) { b, w, d, q };
11
129/// EFLAGS condition codes
1310pub const Condition = enum(u5) {
1411 /// above
......@@ -72,6 +69,12 @@ pub const Condition = enum(u5) {
7269 /// zero
7370 z,
7471
72 // Pseudo conditions
73 /// zero and not parity
74 z_and_np,
75 /// not zero or parity
76 nz_or_p,
77
7578 /// Converts a std.math.CompareOperator into a condition flag,
7679 /// i.e. returns the condition that is true iff the result of the
7780 /// comparison is true. Assumes signed comparison
......@@ -143,6 +146,9 @@ pub const Condition = enum(u5) {
143146 .po => .pe,
144147 .s => .ns,
145148 .z => .nz,
149
150 .z_and_np => .nz_or_p,
151 .nz_or_p => .z_and_np,
146152 };
147153 }
148154};
......@@ -476,7 +482,9 @@ pub const Memory = union(enum) {
476482 dword,
477483 qword,
478484 tbyte,
479 dqword,
485 xword,
486 yword,
487 zword,
480488
481489 pub fn fromSize(size: u32) PtrSize {
482490 return switch (size) {
......@@ -484,7 +492,9 @@ pub const Memory = union(enum) {
484492 2...2 => .word,
485493 3...4 => .dword,
486494 5...8 => .qword,
487 9...16 => .dqword,
495 9...16 => .xword,
496 17...32 => .yword,
497 33...64 => .zword,
488498 else => unreachable,
489499 };
490500 }
......@@ -496,7 +506,9 @@ pub const Memory = union(enum) {
496506 32 => .dword,
497507 64 => .qword,
498508 80 => .tbyte,
499 128 => .dqword,
509 128 => .xword,
510 256 => .yword,
511 512 => .zword,
500512 else => unreachable,
501513 };
502514 }
......@@ -508,7 +520,9 @@ pub const Memory = union(enum) {
508520 .dword => 32,
509521 .qword => 64,
510522 .tbyte => 80,
511 .dqword => 128,
523 .xword => 128,
524 .yword => 256,
525 .zword => 512,
512526 };
513527 }
514528 };
src/arch/x86_64/encoder.zig+154-35
......@@ -151,15 +151,12 @@ pub const Instruction = struct {
151151 moffs.offset,
152152 }),
153153 },
154 .imm => |imm| try writer.print("0x{x}", .{imm.asUnsigned(enc_op.bitSize())}),
154 .imm => |imm| try writer.print("0x{x}", .{imm.asUnsigned(enc_op.immBitSize())}),
155155 }
156156 }
157157
158158 pub fn fmtPrint(op: Operand, enc_op: Encoding.Op) std.fmt.Formatter(fmt) {
159 return .{ .data = .{
160 .op = op,
161 .enc_op = enc_op,
162 } };
159 return .{ .data = .{ .op = op, .enc_op = enc_op } };
163160 }
164161 };
165162
......@@ -209,10 +206,16 @@ pub const Instruction = struct {
209206 const enc = inst.encoding;
210207 const data = enc.data;
211208
212 try inst.encodeLegacyPrefixes(encoder);
213 try inst.encodeMandatoryPrefix(encoder);
214 try inst.encodeRexPrefix(encoder);
215 try inst.encodeOpcode(encoder);
209 if (data.mode.isVex()) {
210 try inst.encodeVexPrefix(encoder);
211 const opc = inst.encoding.opcode();
212 try encoder.opcode_1byte(opc[opc.len - 1]);
213 } else {
214 try inst.encodeLegacyPrefixes(encoder);
215 try inst.encodeMandatoryPrefix(encoder);
216 try inst.encodeRexPrefix(encoder);
217 try inst.encodeOpcode(encoder);
218 }
216219
217220 switch (data.op_en) {
218221 .np, .o => {},
......@@ -222,25 +225,28 @@ pub const Instruction = struct {
222225 .td => try encoder.imm64(inst.ops[0].mem.moffs.offset),
223226 else => {
224227 const mem_op = switch (data.op_en) {
225 .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.ops[0],
226 .rm, .rmi => inst.ops[1],
228 .m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0],
229 .rm, .rmi, .vmi => inst.ops[1],
230 .rvm, .rvmi => inst.ops[2],
227231 else => unreachable,
228232 };
229233 switch (mem_op) {
230234 .reg => |reg| {
231235 const rm = switch (data.op_en) {
232 .m, .mi, .m1, .mc => enc.modRmExt(),
236 .m, .mi, .m1, .mc, .vmi => enc.modRmExt(),
233237 .mr, .mri, .mrc => inst.ops[1].reg.lowEnc(),
234 .rm, .rmi => inst.ops[0].reg.lowEnc(),
238 .rm, .rmi, .rvm, .rvmi => inst.ops[0].reg.lowEnc(),
239 .mvr => inst.ops[2].reg.lowEnc(),
235240 else => unreachable,
236241 };
237242 try encoder.modRm_direct(rm, reg.lowEnc());
238243 },
239244 .mem => |mem| {
240245 const op = switch (data.op_en) {
241 .m, .mi, .m1, .mc => .none,
246 .m, .mi, .m1, .mc, .vmi => .none,
242247 .mr, .mri, .mrc => inst.ops[1],
243 .rm, .rmi => inst.ops[0],
248 .rm, .rmi, .rvm, .rvmi => inst.ops[0],
249 .mvr => inst.ops[2],
244250 else => unreachable,
245251 };
246252 try encodeMemory(enc, mem, op, encoder);
......@@ -250,7 +256,8 @@ pub const Instruction = struct {
250256
251257 switch (data.op_en) {
252258 .mi => try encodeImm(inst.ops[1].imm, data.ops[1], encoder),
253 .rmi, .mri => try encodeImm(inst.ops[2].imm, data.ops[2], encoder),
259 .rmi, .mri, .vmi => try encodeImm(inst.ops[2].imm, data.ops[2], encoder),
260 .rvmi => try encodeImm(inst.ops[3].imm, data.ops[3], encoder),
254261 else => {},
255262 }
256263 },
......@@ -282,11 +289,9 @@ pub const Instruction = struct {
282289 .rep, .repe, .repz => legacy.prefix_f3 = true,
283290 }
284291
285 if (data.mode == .none) {
286 const bit_size = enc.operandBitSize();
287 if (bit_size == 16) {
288 legacy.set16BitOverride();
289 }
292 switch (data.mode) {
293 .short, .rex_short => legacy.set16BitOverride(),
294 else => {},
290295 }
291296
292297 const segment_override: ?Register = switch (op_en) {
......@@ -309,6 +314,7 @@ pub const Instruction = struct {
309314 }
310315 else
311316 null,
317 .vmi, .rvm, .rvmi, .mvr => unreachable,
312318 };
313319 if (segment_override) |seg| {
314320 legacy.setSegmentOverride(seg);
......@@ -322,10 +328,7 @@ pub const Instruction = struct {
322328
323329 var rex = Rex{};
324330 rex.present = inst.encoding.data.mode == .rex;
325 switch (inst.encoding.data.mode) {
326 .long, .sse_long, .sse2_long => rex.w = true,
327 else => {},
328 }
331 rex.w = inst.encoding.data.mode == .long;
329332
330333 switch (op_en) {
331334 .np, .i, .zi, .fd, .td, .d => {},
......@@ -346,11 +349,71 @@ pub const Instruction = struct {
346349 rex.b = b_x_op.isBaseExtended();
347350 rex.x = b_x_op.isIndexExtended();
348351 },
352 .vmi, .rvm, .rvmi, .mvr => unreachable,
349353 }
350354
351355 try encoder.rex(rex);
352356 }
353357
358 fn encodeVexPrefix(inst: Instruction, encoder: anytype) !void {
359 const op_en = inst.encoding.data.op_en;
360 const opc = inst.encoding.opcode();
361 const mand_pre = inst.encoding.mandatoryPrefix();
362
363 var vex = Vex{};
364
365 vex.w = inst.encoding.data.mode.isLong();
366
367 switch (op_en) {
368 .np, .i, .zi, .fd, .td, .d => {},
369 .o, .oi => vex.b = inst.ops[0].reg.isExtended(),
370 .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .vmi, .rvm, .rvmi, .mvr => {
371 const r_op = switch (op_en) {
372 .rm, .rmi, .rvm, .rvmi => inst.ops[0],
373 .mr, .mri, .mrc => inst.ops[1],
374 .mvr => inst.ops[2],
375 .m, .mi, .m1, .mc, .vmi => .none,
376 else => unreachable,
377 };
378 vex.r = r_op.isBaseExtended();
379
380 const b_x_op = switch (op_en) {
381 .rm, .rmi, .vmi => inst.ops[1],
382 .m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0],
383 .rvm, .rvmi => inst.ops[2],
384 else => unreachable,
385 };
386 vex.b = b_x_op.isBaseExtended();
387 vex.x = b_x_op.isIndexExtended();
388 },
389 }
390
391 vex.l = inst.encoding.data.mode.isVecLong();
392
393 vex.p = if (mand_pre) |mand| switch (mand) {
394 0x66 => .@"66",
395 0xf2 => .f2,
396 0xf3 => .f3,
397 else => unreachable,
398 } else .none;
399
400 const leading: usize = if (mand_pre) |_| 1 else 0;
401 assert(opc[leading] == 0x0f);
402 vex.m = switch (opc[leading + 1]) {
403 else => .@"0f",
404 0x38 => .@"0f38",
405 0x3a => .@"0f3a",
406 };
407
408 switch (op_en) {
409 else => {},
410 .vmi => vex.v = inst.ops[0].reg,
411 .rvm, .rvmi => vex.v = inst.ops[1].reg,
412 }
413
414 try encoder.vex(vex);
415 }
416
354417 fn encodeMandatoryPrefix(inst: Instruction, encoder: anytype) !void {
355418 const prefix = inst.encoding.mandatoryPrefix() orelse return;
356419 try encoder.opcode_1byte(prefix);
......@@ -443,8 +506,8 @@ pub const Instruction = struct {
443506 }
444507
445508 fn encodeImm(imm: Immediate, kind: Encoding.Op, encoder: anytype) !void {
446 const raw = imm.asUnsigned(kind.bitSize());
447 switch (kind.bitSize()) {
509 const raw = imm.asUnsigned(kind.immBitSize());
510 switch (kind.immBitSize()) {
448511 8 => try encoder.imm8(@intCast(u8, raw)),
449512 16 => try encoder.imm16(@intCast(u16, raw)),
450513 32 => try encoder.imm32(@intCast(u32, raw)),
......@@ -562,17 +625,48 @@ fn Encoder(comptime T: type, comptime opts: Options) type {
562625 /// or one of reg, index, r/m, base, or opcode-reg might be extended.
563626 ///
564627 /// See struct `Rex` for a description of each field.
565 pub fn rex(self: Self, byte: Rex) !void {
566 if (!byte.present and !byte.isSet()) return;
628 pub fn rex(self: Self, fields: Rex) !void {
629 if (!fields.present and !fields.isSet()) return;
567630
568 var value: u8 = 0b0100_0000;
631 var byte: u8 = 0b0100_0000;
569632
570 if (byte.w) value |= 0b1000;
571 if (byte.r) value |= 0b0100;
572 if (byte.x) value |= 0b0010;
573 if (byte.b) value |= 0b0001;
633 if (fields.w) byte |= 0b1000;
634 if (fields.r) byte |= 0b0100;
635 if (fields.x) byte |= 0b0010;
636 if (fields.b) byte |= 0b0001;
574637
575 try self.writer.writeByte(value);
638 try self.writer.writeByte(byte);
639 }
640
641 /// Encodes a VEX prefix given all the fields
642 ///
643 /// See struct `Vex` for a description of each field.
644 pub fn vex(self: Self, fields: Vex) !void {
645 if (fields.is3Byte()) {
646 try self.writer.writeByte(0b1100_0100);
647
648 try self.writer.writeByte(
649 @as(u8, ~@boolToInt(fields.r)) << 7 |
650 @as(u8, ~@boolToInt(fields.x)) << 6 |
651 @as(u8, ~@boolToInt(fields.b)) << 5 |
652 @as(u8, @enumToInt(fields.m)) << 0,
653 );
654
655 try self.writer.writeByte(
656 @as(u8, @boolToInt(fields.w)) << 7 |
657 @as(u8, ~fields.v.enc()) << 3 |
658 @as(u8, @boolToInt(fields.l)) << 2 |
659 @as(u8, @enumToInt(fields.p)) << 0,
660 );
661 } else {
662 try self.writer.writeByte(0b1100_0101);
663 try self.writer.writeByte(
664 @as(u8, ~@boolToInt(fields.r)) << 7 |
665 @as(u8, ~fields.v.enc()) << 3 |
666 @as(u8, @boolToInt(fields.l)) << 2 |
667 @as(u8, @enumToInt(fields.p)) << 0,
668 );
669 }
576670 }
577671
578672 // ------
......@@ -848,6 +942,31 @@ pub const Rex = struct {
848942 }
849943};
850944
945pub const Vex = struct {
946 w: bool = false,
947 r: bool = false,
948 x: bool = false,
949 b: bool = false,
950 l: bool = false,
951 p: enum(u2) {
952 none = 0b00,
953 @"66" = 0b01,
954 f3 = 0b10,
955 f2 = 0b11,
956 } = .none,
957 m: enum(u5) {
958 @"0f" = 0b0_0001,
959 @"0f38" = 0b0_0010,
960 @"0f3a" = 0b0_0011,
961 _,
962 } = .@"0f",
963 v: Register = .ymm0,
964
965 pub fn is3Byte(vex: Vex) bool {
966 return vex.w or vex.x or vex.b or vex.m != .@"0f";
967 }
968};
969
851970// Tests
852971fn expectEqualHexStrings(expected: []const u8, given: []const u8, assembly: []const u8) !void {
853972 assert(expected.len > 0);
src/arch/x86_64/encodings.zig+1156-870
......@@ -3,933 +3,1219 @@ const Mnemonic = Encoding.Mnemonic;
33const OpEn = Encoding.OpEn;
44const Op = Encoding.Op;
55const Mode = Encoding.Mode;
6const Feature = Encoding.Feature;
67
78const modrm_ext = u3;
89
9pub const Entry = struct { Mnemonic, OpEn, []const Op, []const u8, modrm_ext, Mode };
10pub const Entry = struct { Mnemonic, OpEn, []const Op, []const u8, modrm_ext, Mode, Feature };
1011
1112// TODO move this into a .zon file when Zig is capable of importing .zon files
1213// zig fmt: off
1314pub const table = [_]Entry{
1415 // General-purpose
15 .{ .adc, .zi, &.{ .al, .imm8 }, &.{ 0x14 }, 0, .none },
16 .{ .adc, .zi, &.{ .ax, .imm16 }, &.{ 0x15 }, 0, .none },
17 .{ .adc, .zi, &.{ .eax, .imm32 }, &.{ 0x15 }, 0, .none },
18 .{ .adc, .zi, &.{ .rax, .imm32s }, &.{ 0x15 }, 0, .long },
19 .{ .adc, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 2, .none },
20 .{ .adc, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 2, .rex },
21 .{ .adc, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 2, .none },
22 .{ .adc, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 2, .none },
23 .{ .adc, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 2, .long },
24 .{ .adc, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 2, .none },
25 .{ .adc, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 2, .none },
26 .{ .adc, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 2, .long },
27 .{ .adc, .mr, &.{ .rm8, .r8 }, &.{ 0x10 }, 0, .none },
28 .{ .adc, .mr, &.{ .rm8, .r8 }, &.{ 0x10 }, 0, .rex },
29 .{ .adc, .mr, &.{ .rm16, .r16 }, &.{ 0x11 }, 0, .none },
30 .{ .adc, .mr, &.{ .rm32, .r32 }, &.{ 0x11 }, 0, .none },
31 .{ .adc, .mr, &.{ .rm64, .r64 }, &.{ 0x11 }, 0, .long },
32 .{ .adc, .rm, &.{ .r8, .rm8 }, &.{ 0x12 }, 0, .none },
33 .{ .adc, .rm, &.{ .r8, .rm8 }, &.{ 0x12 }, 0, .rex },
34 .{ .adc, .rm, &.{ .r16, .rm16 }, &.{ 0x13 }, 0, .none },
35 .{ .adc, .rm, &.{ .r32, .rm32 }, &.{ 0x13 }, 0, .none },
36 .{ .adc, .rm, &.{ .r64, .rm64 }, &.{ 0x13 }, 0, .long },
37
38 .{ .add, .zi, &.{ .al, .imm8 }, &.{ 0x04 }, 0, .none },
39 .{ .add, .zi, &.{ .ax, .imm16 }, &.{ 0x05 }, 0, .none },
40 .{ .add, .zi, &.{ .eax, .imm32 }, &.{ 0x05 }, 0, .none },
41 .{ .add, .zi, &.{ .rax, .imm32s }, &.{ 0x05 }, 0, .long },
42 .{ .add, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 0, .none },
43 .{ .add, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 0, .rex },
44 .{ .add, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 0, .none },
45 .{ .add, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 0, .none },
46 .{ .add, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 0, .long },
47 .{ .add, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 0, .none },
48 .{ .add, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 0, .none },
49 .{ .add, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 0, .long },
50 .{ .add, .mr, &.{ .rm8, .r8 }, &.{ 0x00 }, 0, .none },
51 .{ .add, .mr, &.{ .rm8, .r8 }, &.{ 0x00 }, 0, .rex },
52 .{ .add, .mr, &.{ .rm16, .r16 }, &.{ 0x01 }, 0, .none },
53 .{ .add, .mr, &.{ .rm32, .r32 }, &.{ 0x01 }, 0, .none },
54 .{ .add, .mr, &.{ .rm64, .r64 }, &.{ 0x01 }, 0, .long },
55 .{ .add, .rm, &.{ .r8, .rm8 }, &.{ 0x02 }, 0, .none },
56 .{ .add, .rm, &.{ .r8, .rm8 }, &.{ 0x02 }, 0, .rex },
57 .{ .add, .rm, &.{ .r16, .rm16 }, &.{ 0x03 }, 0, .none },
58 .{ .add, .rm, &.{ .r32, .rm32 }, &.{ 0x03 }, 0, .none },
59 .{ .add, .rm, &.{ .r64, .rm64 }, &.{ 0x03 }, 0, .long },
60
61 .{ .@"and", .zi, &.{ .al, .imm8 }, &.{ 0x24 }, 0, .none },
62 .{ .@"and", .zi, &.{ .ax, .imm16 }, &.{ 0x25 }, 0, .none },
63 .{ .@"and", .zi, &.{ .eax, .imm32 }, &.{ 0x25 }, 0, .none },
64 .{ .@"and", .zi, &.{ .rax, .imm32s }, &.{ 0x25 }, 0, .long },
65 .{ .@"and", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 4, .none },
66 .{ .@"and", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 4, .rex },
67 .{ .@"and", .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 4, .none },
68 .{ .@"and", .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 4, .none },
69 .{ .@"and", .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 4, .long },
70 .{ .@"and", .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 4, .none },
71 .{ .@"and", .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 4, .none },
72 .{ .@"and", .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 4, .long },
73 .{ .@"and", .mr, &.{ .rm8, .r8 }, &.{ 0x20 }, 0, .none },
74 .{ .@"and", .mr, &.{ .rm8, .r8 }, &.{ 0x20 }, 0, .rex },
75 .{ .@"and", .mr, &.{ .rm16, .r16 }, &.{ 0x21 }, 0, .none },
76 .{ .@"and", .mr, &.{ .rm32, .r32 }, &.{ 0x21 }, 0, .none },
77 .{ .@"and", .mr, &.{ .rm64, .r64 }, &.{ 0x21 }, 0, .long },
78 .{ .@"and", .rm, &.{ .r8, .rm8 }, &.{ 0x22 }, 0, .none },
79 .{ .@"and", .rm, &.{ .r8, .rm8 }, &.{ 0x22 }, 0, .rex },
80 .{ .@"and", .rm, &.{ .r16, .rm16 }, &.{ 0x23 }, 0, .none },
81 .{ .@"and", .rm, &.{ .r32, .rm32 }, &.{ 0x23 }, 0, .none },
82 .{ .@"and", .rm, &.{ .r64, .rm64 }, &.{ 0x23 }, 0, .long },
83
84 .{ .bsf, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0xbc }, 0, .none },
85 .{ .bsf, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0xbc }, 0, .none },
86 .{ .bsf, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0xbc }, 0, .long },
87
88 .{ .bsr, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0xbd }, 0, .none },
89 .{ .bsr, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0xbd }, 0, .none },
90 .{ .bsr, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0xbd }, 0, .long },
91
92 .{ .bswap, .o, &.{ .r32 }, &.{ 0x0f, 0xc8 }, 0, .none },
93 .{ .bswap, .o, &.{ .r64 }, &.{ 0x0f, 0xc8 }, 0, .long },
94
95 .{ .bt, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xa3 }, 0, .none },
96 .{ .bt, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xa3 }, 0, .none },
97 .{ .bt, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xa3 }, 0, .long },
98 .{ .bt, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 4, .none },
99 .{ .bt, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 4, .none },
100 .{ .bt, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 4, .long },
101
102 .{ .btc, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xbb }, 0, .none },
103 .{ .btc, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xbb }, 0, .none },
104 .{ .btc, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xbb }, 0, .long },
105 .{ .btc, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 7, .none },
106 .{ .btc, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 7, .none },
107 .{ .btc, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 7, .long },
108
109 .{ .btr, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xb3 }, 0, .none },
110 .{ .btr, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xb3 }, 0, .none },
111 .{ .btr, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xb3 }, 0, .long },
112 .{ .btr, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 6, .none },
113 .{ .btr, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 6, .none },
114 .{ .btr, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 6, .long },
115
116 .{ .bts, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xab }, 0, .none },
117 .{ .bts, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xab }, 0, .none },
118 .{ .bts, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xab }, 0, .long },
119 .{ .bts, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 5, .none },
120 .{ .bts, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 5, .none },
121 .{ .bts, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 5, .long },
16 .{ .adc, .zi, &.{ .al, .imm8 }, &.{ 0x14 }, 0, .none, .none },
17 .{ .adc, .zi, &.{ .ax, .imm16 }, &.{ 0x15 }, 0, .short, .none },
18 .{ .adc, .zi, &.{ .eax, .imm32 }, &.{ 0x15 }, 0, .none, .none },
19 .{ .adc, .zi, &.{ .rax, .imm32s }, &.{ 0x15 }, 0, .long, .none },
20 .{ .adc, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 2, .none, .none },
21 .{ .adc, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 2, .rex, .none },
22 .{ .adc, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 2, .short, .none },
23 .{ .adc, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 2, .none, .none },
24 .{ .adc, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 2, .long, .none },
25 .{ .adc, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 2, .short, .none },
26 .{ .adc, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 2, .none, .none },
27 .{ .adc, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 2, .long, .none },
28 .{ .adc, .mr, &.{ .rm8, .r8 }, &.{ 0x10 }, 0, .none, .none },
29 .{ .adc, .mr, &.{ .rm8, .r8 }, &.{ 0x10 }, 0, .rex, .none },
30 .{ .adc, .mr, &.{ .rm16, .r16 }, &.{ 0x11 }, 0, .short, .none },
31 .{ .adc, .mr, &.{ .rm32, .r32 }, &.{ 0x11 }, 0, .none, .none },
32 .{ .adc, .mr, &.{ .rm64, .r64 }, &.{ 0x11 }, 0, .long, .none },
33 .{ .adc, .rm, &.{ .r8, .rm8 }, &.{ 0x12 }, 0, .none, .none },
34 .{ .adc, .rm, &.{ .r8, .rm8 }, &.{ 0x12 }, 0, .rex, .none },
35 .{ .adc, .rm, &.{ .r16, .rm16 }, &.{ 0x13 }, 0, .short, .none },
36 .{ .adc, .rm, &.{ .r32, .rm32 }, &.{ 0x13 }, 0, .none, .none },
37 .{ .adc, .rm, &.{ .r64, .rm64 }, &.{ 0x13 }, 0, .long, .none },
38
39 .{ .add, .zi, &.{ .al, .imm8 }, &.{ 0x04 }, 0, .none, .none },
40 .{ .add, .zi, &.{ .ax, .imm16 }, &.{ 0x05 }, 0, .short, .none },
41 .{ .add, .zi, &.{ .eax, .imm32 }, &.{ 0x05 }, 0, .none, .none },
42 .{ .add, .zi, &.{ .rax, .imm32s }, &.{ 0x05 }, 0, .long, .none },
43 .{ .add, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 0, .none, .none },
44 .{ .add, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 0, .rex, .none },
45 .{ .add, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 0, .short, .none },
46 .{ .add, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 0, .none, .none },
47 .{ .add, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 0, .long, .none },
48 .{ .add, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 0, .short, .none },
49 .{ .add, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 0, .none, .none },
50 .{ .add, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 0, .long, .none },
51 .{ .add, .mr, &.{ .rm8, .r8 }, &.{ 0x00 }, 0, .none, .none },
52 .{ .add, .mr, &.{ .rm8, .r8 }, &.{ 0x00 }, 0, .rex, .none },
53 .{ .add, .mr, &.{ .rm16, .r16 }, &.{ 0x01 }, 0, .short, .none },
54 .{ .add, .mr, &.{ .rm32, .r32 }, &.{ 0x01 }, 0, .none, .none },
55 .{ .add, .mr, &.{ .rm64, .r64 }, &.{ 0x01 }, 0, .long, .none },
56 .{ .add, .rm, &.{ .r8, .rm8 }, &.{ 0x02 }, 0, .none, .none },
57 .{ .add, .rm, &.{ .r8, .rm8 }, &.{ 0x02 }, 0, .rex, .none },
58 .{ .add, .rm, &.{ .r16, .rm16 }, &.{ 0x03 }, 0, .short, .none },
59 .{ .add, .rm, &.{ .r32, .rm32 }, &.{ 0x03 }, 0, .none, .none },
60 .{ .add, .rm, &.{ .r64, .rm64 }, &.{ 0x03 }, 0, .long, .none },
61
62 .{ .@"and", .zi, &.{ .al, .imm8 }, &.{ 0x24 }, 0, .none, .none },
63 .{ .@"and", .zi, &.{ .ax, .imm16 }, &.{ 0x25 }, 0, .short, .none },
64 .{ .@"and", .zi, &.{ .eax, .imm32 }, &.{ 0x25 }, 0, .none, .none },
65 .{ .@"and", .zi, &.{ .rax, .imm32s }, &.{ 0x25 }, 0, .long, .none },
66 .{ .@"and", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 4, .none, .none },
67 .{ .@"and", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 4, .rex, .none },
68 .{ .@"and", .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 4, .short, .none },
69 .{ .@"and", .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 4, .none, .none },
70 .{ .@"and", .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 4, .long, .none },
71 .{ .@"and", .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 4, .short, .none },
72 .{ .@"and", .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 4, .none, .none },
73 .{ .@"and", .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 4, .long, .none },
74 .{ .@"and", .mr, &.{ .rm8, .r8 }, &.{ 0x20 }, 0, .none, .none },
75 .{ .@"and", .mr, &.{ .rm8, .r8 }, &.{ 0x20 }, 0, .rex, .none },
76 .{ .@"and", .mr, &.{ .rm16, .r16 }, &.{ 0x21 }, 0, .short, .none },
77 .{ .@"and", .mr, &.{ .rm32, .r32 }, &.{ 0x21 }, 0, .none, .none },
78 .{ .@"and", .mr, &.{ .rm64, .r64 }, &.{ 0x21 }, 0, .long, .none },
79 .{ .@"and", .rm, &.{ .r8, .rm8 }, &.{ 0x22 }, 0, .none, .none },
80 .{ .@"and", .rm, &.{ .r8, .rm8 }, &.{ 0x22 }, 0, .rex, .none },
81 .{ .@"and", .rm, &.{ .r16, .rm16 }, &.{ 0x23 }, 0, .short, .none },
82 .{ .@"and", .rm, &.{ .r32, .rm32 }, &.{ 0x23 }, 0, .none, .none },
83 .{ .@"and", .rm, &.{ .r64, .rm64 }, &.{ 0x23 }, 0, .long, .none },
84
85 .{ .bsf, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0xbc }, 0, .short, .none },
86 .{ .bsf, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0xbc }, 0, .none, .none },
87 .{ .bsf, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0xbc }, 0, .long, .none },
88
89 .{ .bsr, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0xbd }, 0, .short, .none },
90 .{ .bsr, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0xbd }, 0, .none, .none },
91 .{ .bsr, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0xbd }, 0, .long, .none },
92
93 .{ .bswap, .o, &.{ .r32 }, &.{ 0x0f, 0xc8 }, 0, .none, .none },
94 .{ .bswap, .o, &.{ .r64 }, &.{ 0x0f, 0xc8 }, 0, .long, .none },
95
96 .{ .bt, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xa3 }, 0, .short, .none },
97 .{ .bt, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xa3 }, 0, .none, .none },
98 .{ .bt, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xa3 }, 0, .long, .none },
99 .{ .bt, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 4, .short, .none },
100 .{ .bt, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 4, .none, .none },
101 .{ .bt, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 4, .long, .none },
102
103 .{ .btc, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xbb }, 0, .short, .none },
104 .{ .btc, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xbb }, 0, .none, .none },
105 .{ .btc, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xbb }, 0, .long, .none },
106 .{ .btc, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 7, .short, .none },
107 .{ .btc, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 7, .none, .none },
108 .{ .btc, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 7, .long, .none },
109
110 .{ .btr, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xb3 }, 0, .short, .none },
111 .{ .btr, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xb3 }, 0, .none, .none },
112 .{ .btr, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xb3 }, 0, .long, .none },
113 .{ .btr, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 6, .short, .none },
114 .{ .btr, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 6, .none, .none },
115 .{ .btr, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 6, .long, .none },
116
117 .{ .bts, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xab }, 0, .short, .none },
118 .{ .bts, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xab }, 0, .none, .none },
119 .{ .bts, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xab }, 0, .long, .none },
120 .{ .bts, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 5, .short, .none },
121 .{ .bts, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 5, .none, .none },
122 .{ .bts, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 5, .long, .none },
122123
123124 // This is M encoding according to Intel, but D makes more sense here.
124 .{ .call, .d, &.{ .rel32 }, &.{ 0xe8 }, 0, .none },
125 .{ .call, .m, &.{ .rm64 }, &.{ 0xff }, 2, .none },
126
127 .{ .cbw, .np, &.{ .o16 }, &.{ 0x98 }, 0, .none },
128 .{ .cwde, .np, &.{ .o32 }, &.{ 0x98 }, 0, .none },
129 .{ .cdqe, .np, &.{ .o64 }, &.{ 0x98 }, 0, .long },
130
131 .{ .cwd, .np, &.{ .o16 }, &.{ 0x99 }, 0, .none },
132 .{ .cdq, .np, &.{ .o32 }, &.{ 0x99 }, 0, .none },
133 .{ .cqo, .np, &.{ .o64 }, &.{ 0x99 }, 0, .long },
134
135 .{ .cmova, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x47 }, 0, .none },
136 .{ .cmova, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x47 }, 0, .none },
137 .{ .cmova, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x47 }, 0, .long },
138 .{ .cmovae, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .none },
139 .{ .cmovae, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none },
140 .{ .cmovae, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long },
141 .{ .cmovb, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .none },
142 .{ .cmovb, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none },
143 .{ .cmovb, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long },
144 .{ .cmovbe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x46 }, 0, .none },
145 .{ .cmovbe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x46 }, 0, .none },
146 .{ .cmovbe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x46 }, 0, .long },
147 .{ .cmovc, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .none },
148 .{ .cmovc, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none },
149 .{ .cmovc, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long },
150 .{ .cmove, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x44 }, 0, .none },
151 .{ .cmove, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x44 }, 0, .none },
152 .{ .cmove, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x44 }, 0, .long },
153 .{ .cmovg, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4f }, 0, .none },
154 .{ .cmovg, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4f }, 0, .none },
155 .{ .cmovg, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4f }, 0, .long },
156 .{ .cmovge, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4d }, 0, .none },
157 .{ .cmovge, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4d }, 0, .none },
158 .{ .cmovge, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4d }, 0, .long },
159 .{ .cmovl, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4c }, 0, .none },
160 .{ .cmovl, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4c }, 0, .none },
161 .{ .cmovl, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4c }, 0, .long },
162 .{ .cmovle, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4e }, 0, .none },
163 .{ .cmovle, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4e }, 0, .none },
164 .{ .cmovle, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4e }, 0, .long },
165 .{ .cmovna, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x46 }, 0, .none },
166 .{ .cmovna, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x46 }, 0, .none },
167 .{ .cmovna, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x46 }, 0, .long },
168 .{ .cmovnae, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .none },
169 .{ .cmovnae, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none },
170 .{ .cmovnae, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long },
171 .{ .cmovnb, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .none },
172 .{ .cmovnb, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none },
173 .{ .cmovnb, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long },
174 .{ .cmovnbe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x47 }, 0, .none },
175 .{ .cmovnbe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x47 }, 0, .none },
176 .{ .cmovnbe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x47 }, 0, .long },
177 .{ .cmovnc, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .none },
178 .{ .cmovnc, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none },
179 .{ .cmovnc, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long },
180 .{ .cmovne, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x45 }, 0, .none },
181 .{ .cmovne, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x45 }, 0, .none },
182 .{ .cmovne, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x45 }, 0, .long },
183 .{ .cmovng, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4e }, 0, .none },
184 .{ .cmovng, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4e }, 0, .none },
185 .{ .cmovng, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4e }, 0, .long },
186 .{ .cmovnge, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4c }, 0, .none },
187 .{ .cmovnge, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4c }, 0, .none },
188 .{ .cmovnge, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4c }, 0, .long },
189 .{ .cmovnl, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4d }, 0, .none },
190 .{ .cmovnl, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4d }, 0, .none },
191 .{ .cmovnl, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4d }, 0, .long },
192 .{ .cmovnle, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4f }, 0, .none },
193 .{ .cmovnle, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4f }, 0, .none },
194 .{ .cmovnle, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4f }, 0, .long },
195 .{ .cmovno, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x41 }, 0, .none },
196 .{ .cmovno, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x41 }, 0, .none },
197 .{ .cmovno, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x41 }, 0, .long },
198 .{ .cmovnp, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4b }, 0, .none },
199 .{ .cmovnp, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4b }, 0, .none },
200 .{ .cmovnp, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4b }, 0, .long },
201 .{ .cmovns, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x49 }, 0, .none },
202 .{ .cmovns, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x49 }, 0, .none },
203 .{ .cmovns, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x49 }, 0, .long },
204 .{ .cmovnz, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x45 }, 0, .none },
205 .{ .cmovnz, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x45 }, 0, .none },
206 .{ .cmovnz, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x45 }, 0, .long },
207 .{ .cmovo, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x40 }, 0, .none },
208 .{ .cmovo, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x40 }, 0, .none },
209 .{ .cmovo, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x40 }, 0, .long },
210 .{ .cmovp, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4a }, 0, .none },
211 .{ .cmovp, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4a }, 0, .none },
212 .{ .cmovp, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4a }, 0, .long },
213 .{ .cmovpe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4a }, 0, .none },
214 .{ .cmovpe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4a }, 0, .none },
215 .{ .cmovpe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4a }, 0, .long },
216 .{ .cmovpo, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4b }, 0, .none },
217 .{ .cmovpo, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4b }, 0, .none },
218 .{ .cmovpo, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4b }, 0, .long },
219 .{ .cmovs, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x48 }, 0, .none },
220 .{ .cmovs, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x48 }, 0, .none },
221 .{ .cmovs, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x48 }, 0, .long },
222 .{ .cmovz, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x44 }, 0, .none },
223 .{ .cmovz, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x44 }, 0, .none },
224 .{ .cmovz, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x44 }, 0, .long },
225
226 .{ .cmp, .zi, &.{ .al, .imm8 }, &.{ 0x3c }, 0, .none },
227 .{ .cmp, .zi, &.{ .ax, .imm16 }, &.{ 0x3d }, 0, .none },
228 .{ .cmp, .zi, &.{ .eax, .imm32 }, &.{ 0x3d }, 0, .none },
229 .{ .cmp, .zi, &.{ .rax, .imm32s }, &.{ 0x3d }, 0, .long },
230 .{ .cmp, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 7, .none },
231 .{ .cmp, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 7, .rex },
232 .{ .cmp, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 7, .none },
233 .{ .cmp, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 7, .none },
234 .{ .cmp, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 7, .long },
235 .{ .cmp, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 7, .none },
236 .{ .cmp, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 7, .none },
237 .{ .cmp, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 7, .long },
238 .{ .cmp, .mr, &.{ .rm8, .r8 }, &.{ 0x38 }, 0, .none },
239 .{ .cmp, .mr, &.{ .rm8, .r8 }, &.{ 0x38 }, 0, .rex },
240 .{ .cmp, .mr, &.{ .rm16, .r16 }, &.{ 0x39 }, 0, .none },
241 .{ .cmp, .mr, &.{ .rm32, .r32 }, &.{ 0x39 }, 0, .none },
242 .{ .cmp, .mr, &.{ .rm64, .r64 }, &.{ 0x39 }, 0, .long },
243 .{ .cmp, .rm, &.{ .r8, .rm8 }, &.{ 0x3a }, 0, .none },
244 .{ .cmp, .rm, &.{ .r8, .rm8 }, &.{ 0x3a }, 0, .rex },
245 .{ .cmp, .rm, &.{ .r16, .rm16 }, &.{ 0x3b }, 0, .none },
246 .{ .cmp, .rm, &.{ .r32, .rm32 }, &.{ 0x3b }, 0, .none },
247 .{ .cmp, .rm, &.{ .r64, .rm64 }, &.{ 0x3b }, 0, .long },
248
249 .{ .cmps, .np, &.{ .m8, .m8 }, &.{ 0xa6 }, 0, .none },
250 .{ .cmps, .np, &.{ .m16, .m16 }, &.{ 0xa7 }, 0, .none },
251 .{ .cmps, .np, &.{ .m32, .m32 }, &.{ 0xa7 }, 0, .none },
252 .{ .cmps, .np, &.{ .m64, .m64 }, &.{ 0xa7 }, 0, .long },
253
254 .{ .cmpsb, .np, &.{}, &.{ 0xa6 }, 0, .none },
255 .{ .cmpsw, .np, &.{}, &.{ 0xa7 }, 0, .short },
256 .{ .cmpsd, .np, &.{}, &.{ 0xa7 }, 0, .none },
257 .{ .cmpsq, .np, &.{}, &.{ 0xa7 }, 0, .long },
258
259 .{ .cmpxchg, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xb0 }, 0, .none },
260 .{ .cmpxchg, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xb0 }, 0, .rex },
261 .{ .cmpxchg, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xb1 }, 0, .none },
262 .{ .cmpxchg, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xb1 }, 0, .none },
263 .{ .cmpxchg, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xb1 }, 0, .long },
264
265 .{ .cmpxchg8b , .m, &.{ .m64 }, &.{ 0x0f, 0xc7 }, 1, .none },
266 .{ .cmpxchg16b, .m, &.{ .m128 }, &.{ 0x0f, 0xc7 }, 1, .long },
267
268 .{ .div, .m, &.{ .rm8 }, &.{ 0xf6 }, 6, .none },
269 .{ .div, .m, &.{ .rm8 }, &.{ 0xf6 }, 6, .rex },
270 .{ .div, .m, &.{ .rm16 }, &.{ 0xf7 }, 6, .none },
271 .{ .div, .m, &.{ .rm32 }, &.{ 0xf7 }, 6, .none },
272 .{ .div, .m, &.{ .rm64 }, &.{ 0xf7 }, 6, .long },
273
274 .{ .fisttp, .m, &.{ .m16 }, &.{ 0xdf }, 1, .fpu },
275 .{ .fisttp, .m, &.{ .m32 }, &.{ 0xdb }, 1, .fpu },
276 .{ .fisttp, .m, &.{ .m64 }, &.{ 0xdd }, 1, .fpu },
277
278 .{ .fld, .m, &.{ .m32 }, &.{ 0xd9 }, 0, .fpu },
279 .{ .fld, .m, &.{ .m64 }, &.{ 0xdd }, 0, .fpu },
280 .{ .fld, .m, &.{ .m80 }, &.{ 0xdb }, 5, .fpu },
281
282 .{ .idiv, .m, &.{ .rm8 }, &.{ 0xf6 }, 7, .none },
283 .{ .idiv, .m, &.{ .rm8 }, &.{ 0xf6 }, 7, .rex },
284 .{ .idiv, .m, &.{ .rm16 }, &.{ 0xf7 }, 7, .none },
285 .{ .idiv, .m, &.{ .rm32 }, &.{ 0xf7 }, 7, .none },
286 .{ .idiv, .m, &.{ .rm64 }, &.{ 0xf7 }, 7, .long },
287
288 .{ .imul, .m, &.{ .rm8 }, &.{ 0xf6 }, 5, .none },
289 .{ .imul, .m, &.{ .rm8 }, &.{ 0xf6 }, 5, .rex },
290 .{ .imul, .m, &.{ .rm16, }, &.{ 0xf7 }, 5, .none },
291 .{ .imul, .m, &.{ .rm32, }, &.{ 0xf7 }, 5, .none },
292 .{ .imul, .m, &.{ .rm64, }, &.{ 0xf7 }, 5, .long },
293 .{ .imul, .rm, &.{ .r16, .rm16, }, &.{ 0x0f, 0xaf }, 0, .none },
294 .{ .imul, .rm, &.{ .r32, .rm32, }, &.{ 0x0f, 0xaf }, 0, .none },
295 .{ .imul, .rm, &.{ .r64, .rm64, }, &.{ 0x0f, 0xaf }, 0, .long },
296 .{ .imul, .rmi, &.{ .r16, .rm16, .imm8s }, &.{ 0x6b }, 0, .none },
297 .{ .imul, .rmi, &.{ .r32, .rm32, .imm8s }, &.{ 0x6b }, 0, .none },
298 .{ .imul, .rmi, &.{ .r64, .rm64, .imm8s }, &.{ 0x6b }, 0, .long },
299 .{ .imul, .rmi, &.{ .r16, .rm16, .imm16 }, &.{ 0x69 }, 0, .none },
300 .{ .imul, .rmi, &.{ .r32, .rm32, .imm32 }, &.{ 0x69 }, 0, .none },
301 .{ .imul, .rmi, &.{ .r64, .rm64, .imm32 }, &.{ 0x69 }, 0, .long },
302
303 .{ .int3, .np, &.{}, &.{ 0xcc }, 0, .none },
304
305 .{ .ja, .d, &.{ .rel32 }, &.{ 0x0f, 0x87 }, 0, .none },
306 .{ .jae, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none },
307 .{ .jb, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none },
308 .{ .jbe, .d, &.{ .rel32 }, &.{ 0x0f, 0x86 }, 0, .none },
309 .{ .jc, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none },
310 .{ .jrcxz, .d, &.{ .rel32 }, &.{ 0xe3 }, 0, .none },
311 .{ .je, .d, &.{ .rel32 }, &.{ 0x0f, 0x84 }, 0, .none },
312 .{ .jg, .d, &.{ .rel32 }, &.{ 0x0f, 0x8f }, 0, .none },
313 .{ .jge, .d, &.{ .rel32 }, &.{ 0x0f, 0x8d }, 0, .none },
314 .{ .jl, .d, &.{ .rel32 }, &.{ 0x0f, 0x8c }, 0, .none },
315 .{ .jle, .d, &.{ .rel32 }, &.{ 0x0f, 0x8e }, 0, .none },
316 .{ .jna, .d, &.{ .rel32 }, &.{ 0x0f, 0x86 }, 0, .none },
317 .{ .jnae, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none },
318 .{ .jnb, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none },
319 .{ .jnbe, .d, &.{ .rel32 }, &.{ 0x0f, 0x87 }, 0, .none },
320 .{ .jnc, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none },
321 .{ .jne, .d, &.{ .rel32 }, &.{ 0x0f, 0x85 }, 0, .none },
322 .{ .jng, .d, &.{ .rel32 }, &.{ 0x0f, 0x8e }, 0, .none },
323 .{ .jnge, .d, &.{ .rel32 }, &.{ 0x0f, 0x8c }, 0, .none },
324 .{ .jnl, .d, &.{ .rel32 }, &.{ 0x0f, 0x8d }, 0, .none },
325 .{ .jnle, .d, &.{ .rel32 }, &.{ 0x0f, 0x8f }, 0, .none },
326 .{ .jno, .d, &.{ .rel32 }, &.{ 0x0f, 0x81 }, 0, .none },
327 .{ .jnp, .d, &.{ .rel32 }, &.{ 0x0f, 0x8b }, 0, .none },
328 .{ .jns, .d, &.{ .rel32 }, &.{ 0x0f, 0x89 }, 0, .none },
329 .{ .jnz, .d, &.{ .rel32 }, &.{ 0x0f, 0x85 }, 0, .none },
330 .{ .jo, .d, &.{ .rel32 }, &.{ 0x0f, 0x80 }, 0, .none },
331 .{ .jp, .d, &.{ .rel32 }, &.{ 0x0f, 0x8a }, 0, .none },
332 .{ .jpe, .d, &.{ .rel32 }, &.{ 0x0f, 0x8a }, 0, .none },
333 .{ .jpo, .d, &.{ .rel32 }, &.{ 0x0f, 0x8b }, 0, .none },
334 .{ .js, .d, &.{ .rel32 }, &.{ 0x0f, 0x88 }, 0, .none },
335 .{ .jz, .d, &.{ .rel32 }, &.{ 0x0f, 0x84 }, 0, .none },
336
337 .{ .jmp, .d, &.{ .rel32 }, &.{ 0xe9 }, 0, .none },
338 .{ .jmp, .m, &.{ .rm64 }, &.{ 0xff }, 4, .none },
339
340 .{ .lea, .rm, &.{ .r16, .m }, &.{ 0x8d }, 0, .none },
341 .{ .lea, .rm, &.{ .r32, .m }, &.{ 0x8d }, 0, .none },
342 .{ .lea, .rm, &.{ .r64, .m }, &.{ 0x8d }, 0, .long },
343
344 .{ .lfence, .np, &.{}, &.{ 0x0f, 0xae, 0xe8 }, 0, .none },
345
346 .{ .lods, .np, &.{ .m8 }, &.{ 0xac }, 0, .none },
347 .{ .lods, .np, &.{ .m16 }, &.{ 0xad }, 0, .none },
348 .{ .lods, .np, &.{ .m32 }, &.{ 0xad }, 0, .none },
349 .{ .lods, .np, &.{ .m64 }, &.{ 0xad }, 0, .long },
350
351 .{ .lodsb, .np, &.{}, &.{ 0xac }, 0, .none },
352 .{ .lodsw, .np, &.{}, &.{ 0xad }, 0, .short },
353 .{ .lodsd, .np, &.{}, &.{ 0xad }, 0, .none },
354 .{ .lodsq, .np, &.{}, &.{ 0xad }, 0, .long },
355
356 .{ .lzcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .none },
357 .{ .lzcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .none },
358 .{ .lzcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .long },
359
360 .{ .mfence, .np, &.{}, &.{ 0x0f, 0xae, 0xf0 }, 0, .none },
361
362 .{ .mov, .mr, &.{ .rm8, .r8 }, &.{ 0x88 }, 0, .none },
363 .{ .mov, .mr, &.{ .rm8, .r8 }, &.{ 0x88 }, 0, .rex },
364 .{ .mov, .mr, &.{ .rm16, .r16 }, &.{ 0x89 }, 0, .none },
365 .{ .mov, .mr, &.{ .rm32, .r32 }, &.{ 0x89 }, 0, .none },
366 .{ .mov, .mr, &.{ .rm64, .r64 }, &.{ 0x89 }, 0, .long },
367 .{ .mov, .rm, &.{ .r8, .rm8 }, &.{ 0x8a }, 0, .none },
368 .{ .mov, .rm, &.{ .r8, .rm8 }, &.{ 0x8a }, 0, .rex },
369 .{ .mov, .rm, &.{ .r16, .rm16 }, &.{ 0x8b }, 0, .none },
370 .{ .mov, .rm, &.{ .r32, .rm32 }, &.{ 0x8b }, 0, .none },
371 .{ .mov, .rm, &.{ .r64, .rm64 }, &.{ 0x8b }, 0, .long },
372 .{ .mov, .mr, &.{ .rm16, .sreg }, &.{ 0x8c }, 0, .none },
373 .{ .mov, .mr, &.{ .rm64, .sreg }, &.{ 0x8c }, 0, .long },
374 .{ .mov, .rm, &.{ .sreg, .rm16 }, &.{ 0x8e }, 0, .none },
375 .{ .mov, .rm, &.{ .sreg, .rm64 }, &.{ 0x8e }, 0, .long },
376 .{ .mov, .fd, &.{ .al, .moffs }, &.{ 0xa0 }, 0, .none },
377 .{ .mov, .fd, &.{ .ax, .moffs }, &.{ 0xa1 }, 0, .none },
378 .{ .mov, .fd, &.{ .eax, .moffs }, &.{ 0xa1 }, 0, .none },
379 .{ .mov, .fd, &.{ .rax, .moffs }, &.{ 0xa1 }, 0, .long },
380 .{ .mov, .td, &.{ .moffs, .al }, &.{ 0xa2 }, 0, .none },
381 .{ .mov, .td, &.{ .moffs, .ax }, &.{ 0xa3 }, 0, .none },
382 .{ .mov, .td, &.{ .moffs, .eax }, &.{ 0xa3 }, 0, .none },
383 .{ .mov, .td, &.{ .moffs, .rax }, &.{ 0xa3 }, 0, .long },
384 .{ .mov, .oi, &.{ .r8, .imm8 }, &.{ 0xb0 }, 0, .none },
385 .{ .mov, .oi, &.{ .r8, .imm8 }, &.{ 0xb0 }, 0, .rex },
386 .{ .mov, .oi, &.{ .r16, .imm16 }, &.{ 0xb8 }, 0, .none },
387 .{ .mov, .oi, &.{ .r32, .imm32 }, &.{ 0xb8 }, 0, .none },
388 .{ .mov, .oi, &.{ .r64, .imm64 }, &.{ 0xb8 }, 0, .long },
389 .{ .mov, .mi, &.{ .rm8, .imm8 }, &.{ 0xc6 }, 0, .none },
390 .{ .mov, .mi, &.{ .rm8, .imm8 }, &.{ 0xc6 }, 0, .rex },
391 .{ .mov, .mi, &.{ .rm16, .imm16 }, &.{ 0xc7 }, 0, .none },
392 .{ .mov, .mi, &.{ .rm32, .imm32 }, &.{ 0xc7 }, 0, .none },
393 .{ .mov, .mi, &.{ .rm64, .imm32s }, &.{ 0xc7 }, 0, .long },
394
395 .{ .movbe, .rm, &.{ .r16, .m16 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .none },
396 .{ .movbe, .rm, &.{ .r32, .m32 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .none },
397 .{ .movbe, .rm, &.{ .r64, .m64 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .long },
398 .{ .movbe, .mr, &.{ .m16, .r16 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .none },
399 .{ .movbe, .mr, &.{ .m32, .r32 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .none },
400 .{ .movbe, .mr, &.{ .m64, .r64 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .long },
401
402 .{ .movs, .np, &.{ .m8, .m8 }, &.{ 0xa4 }, 0, .none },
403 .{ .movs, .np, &.{ .m16, .m16 }, &.{ 0xa5 }, 0, .none },
404 .{ .movs, .np, &.{ .m32, .m32 }, &.{ 0xa5 }, 0, .none },
405 .{ .movs, .np, &.{ .m64, .m64 }, &.{ 0xa5 }, 0, .long },
406
407 .{ .movsb, .np, &.{}, &.{ 0xa4 }, 0, .none },
408 .{ .movsw, .np, &.{}, &.{ 0xa5 }, 0, .short },
409 .{ .movsd, .np, &.{}, &.{ 0xa5 }, 0, .none },
410 .{ .movsq, .np, &.{}, &.{ 0xa5 }, 0, .long },
411
412 .{ .movsx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xbe }, 0, .none },
413 .{ .movsx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xbe }, 0, .rex },
414 .{ .movsx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xbe }, 0, .none },
415 .{ .movsx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xbe }, 0, .rex },
416 .{ .movsx, .rm, &.{ .r64, .rm8 }, &.{ 0x0f, 0xbe }, 0, .long },
417 .{ .movsx, .rm, &.{ .r32, .rm16 }, &.{ 0x0f, 0xbf }, 0, .none },
418 .{ .movsx, .rm, &.{ .r64, .rm16 }, &.{ 0x0f, 0xbf }, 0, .long },
125 .{ .call, .d, &.{ .rel32 }, &.{ 0xe8 }, 0, .none, .none },
126 .{ .call, .m, &.{ .rm64 }, &.{ 0xff }, 2, .none, .none },
127
128 .{ .cbw, .np, &.{ .o16 }, &.{ 0x98 }, 0, .short, .none },
129 .{ .cwde, .np, &.{ .o32 }, &.{ 0x98 }, 0, .none, .none },
130 .{ .cdqe, .np, &.{ .o64 }, &.{ 0x98 }, 0, .long, .none },
131
132 .{ .cwd, .np, &.{ .o16 }, &.{ 0x99 }, 0, .short, .none },
133 .{ .cdq, .np, &.{ .o32 }, &.{ 0x99 }, 0, .none, .none },
134 .{ .cqo, .np, &.{ .o64 }, &.{ 0x99 }, 0, .long, .none },
135
136 .{ .cmova, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x47 }, 0, .short, .none },
137 .{ .cmova, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x47 }, 0, .none, .none },
138 .{ .cmova, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x47 }, 0, .long, .none },
139 .{ .cmovae, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .short, .none },
140 .{ .cmovae, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none, .none },
141 .{ .cmovae, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long, .none },
142 .{ .cmovb, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .short, .none },
143 .{ .cmovb, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none, .none },
144 .{ .cmovb, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long, .none },
145 .{ .cmovbe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x46 }, 0, .short, .none },
146 .{ .cmovbe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x46 }, 0, .none, .none },
147 .{ .cmovbe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x46 }, 0, .long, .none },
148 .{ .cmovc, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .short, .none },
149 .{ .cmovc, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none, .none },
150 .{ .cmovc, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long, .none },
151 .{ .cmove, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x44 }, 0, .short, .none },
152 .{ .cmove, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x44 }, 0, .none, .none },
153 .{ .cmove, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x44 }, 0, .long, .none },
154 .{ .cmovg, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4f }, 0, .short, .none },
155 .{ .cmovg, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4f }, 0, .none, .none },
156 .{ .cmovg, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4f }, 0, .long, .none },
157 .{ .cmovge, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4d }, 0, .short, .none },
158 .{ .cmovge, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4d }, 0, .none, .none },
159 .{ .cmovge, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4d }, 0, .long, .none },
160 .{ .cmovl, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4c }, 0, .short, .none },
161 .{ .cmovl, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4c }, 0, .none, .none },
162 .{ .cmovl, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4c }, 0, .long, .none },
163 .{ .cmovle, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4e }, 0, .short, .none },
164 .{ .cmovle, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4e }, 0, .none, .none },
165 .{ .cmovle, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4e }, 0, .long, .none },
166 .{ .cmovna, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x46 }, 0, .short, .none },
167 .{ .cmovna, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x46 }, 0, .none, .none },
168 .{ .cmovna, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x46 }, 0, .long, .none },
169 .{ .cmovnae, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .short, .none },
170 .{ .cmovnae, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none, .none },
171 .{ .cmovnae, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long, .none },
172 .{ .cmovnb, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .short, .none },
173 .{ .cmovnb, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none, .none },
174 .{ .cmovnb, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long, .none },
175 .{ .cmovnbe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x47 }, 0, .short, .none },
176 .{ .cmovnbe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x47 }, 0, .none, .none },
177 .{ .cmovnbe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x47 }, 0, .long, .none },
178 .{ .cmovnc, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .short, .none },
179 .{ .cmovnc, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none, .none },
180 .{ .cmovnc, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long, .none },
181 .{ .cmovne, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x45 }, 0, .short, .none },
182 .{ .cmovne, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x45 }, 0, .none, .none },
183 .{ .cmovne, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x45 }, 0, .long, .none },
184 .{ .cmovng, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4e }, 0, .short, .none },
185 .{ .cmovng, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4e }, 0, .none, .none },
186 .{ .cmovng, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4e }, 0, .long, .none },
187 .{ .cmovnge, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4c }, 0, .short, .none },
188 .{ .cmovnge, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4c }, 0, .none, .none },
189 .{ .cmovnge, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4c }, 0, .long, .none },
190 .{ .cmovnl, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4d }, 0, .short, .none },
191 .{ .cmovnl, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4d }, 0, .none, .none },
192 .{ .cmovnl, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4d }, 0, .long, .none },
193 .{ .cmovnle, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4f }, 0, .short, .none },
194 .{ .cmovnle, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4f }, 0, .none, .none },
195 .{ .cmovnle, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4f }, 0, .long, .none },
196 .{ .cmovno, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x41 }, 0, .short, .none },
197 .{ .cmovno, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x41 }, 0, .none, .none },
198 .{ .cmovno, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x41 }, 0, .long, .none },
199 .{ .cmovnp, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4b }, 0, .short, .none },
200 .{ .cmovnp, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4b }, 0, .none, .none },
201 .{ .cmovnp, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4b }, 0, .long, .none },
202 .{ .cmovns, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x49 }, 0, .short, .none },
203 .{ .cmovns, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x49 }, 0, .none, .none },
204 .{ .cmovns, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x49 }, 0, .long, .none },
205 .{ .cmovnz, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x45 }, 0, .short, .none },
206 .{ .cmovnz, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x45 }, 0, .none, .none },
207 .{ .cmovnz, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x45 }, 0, .long, .none },
208 .{ .cmovo, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x40 }, 0, .short, .none },
209 .{ .cmovo, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x40 }, 0, .none, .none },
210 .{ .cmovo, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x40 }, 0, .long, .none },
211 .{ .cmovp, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4a }, 0, .short, .none },
212 .{ .cmovp, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4a }, 0, .none, .none },
213 .{ .cmovp, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4a }, 0, .long, .none },
214 .{ .cmovpe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4a }, 0, .short, .none },
215 .{ .cmovpe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4a }, 0, .none, .none },
216 .{ .cmovpe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4a }, 0, .long, .none },
217 .{ .cmovpo, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4b }, 0, .short, .none },
218 .{ .cmovpo, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4b }, 0, .none, .none },
219 .{ .cmovpo, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4b }, 0, .long, .none },
220 .{ .cmovs, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x48 }, 0, .short, .none },
221 .{ .cmovs, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x48 }, 0, .none, .none },
222 .{ .cmovs, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x48 }, 0, .long, .none },
223 .{ .cmovz, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x44 }, 0, .short, .none },
224 .{ .cmovz, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x44 }, 0, .none, .none },
225 .{ .cmovz, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x44 }, 0, .long, .none },
226
227 .{ .cmp, .zi, &.{ .al, .imm8 }, &.{ 0x3c }, 0, .none, .none },
228 .{ .cmp, .zi, &.{ .ax, .imm16 }, &.{ 0x3d }, 0, .short, .none },
229 .{ .cmp, .zi, &.{ .eax, .imm32 }, &.{ 0x3d }, 0, .none, .none },
230 .{ .cmp, .zi, &.{ .rax, .imm32s }, &.{ 0x3d }, 0, .long, .none },
231 .{ .cmp, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 7, .none, .none },
232 .{ .cmp, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 7, .rex, .none },
233 .{ .cmp, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 7, .short, .none },
234 .{ .cmp, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 7, .none, .none },
235 .{ .cmp, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 7, .long, .none },
236 .{ .cmp, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 7, .short, .none },
237 .{ .cmp, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 7, .none, .none },
238 .{ .cmp, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 7, .long, .none },
239 .{ .cmp, .mr, &.{ .rm8, .r8 }, &.{ 0x38 }, 0, .none, .none },
240 .{ .cmp, .mr, &.{ .rm8, .r8 }, &.{ 0x38 }, 0, .rex, .none },
241 .{ .cmp, .mr, &.{ .rm16, .r16 }, &.{ 0x39 }, 0, .short, .none },
242 .{ .cmp, .mr, &.{ .rm32, .r32 }, &.{ 0x39 }, 0, .none, .none },
243 .{ .cmp, .mr, &.{ .rm64, .r64 }, &.{ 0x39 }, 0, .long, .none },
244 .{ .cmp, .rm, &.{ .r8, .rm8 }, &.{ 0x3a }, 0, .none, .none },
245 .{ .cmp, .rm, &.{ .r8, .rm8 }, &.{ 0x3a }, 0, .rex, .none },
246 .{ .cmp, .rm, &.{ .r16, .rm16 }, &.{ 0x3b }, 0, .short, .none },
247 .{ .cmp, .rm, &.{ .r32, .rm32 }, &.{ 0x3b }, 0, .none, .none },
248 .{ .cmp, .rm, &.{ .r64, .rm64 }, &.{ 0x3b }, 0, .long, .none },
249
250 .{ .cmps, .np, &.{ .m8, .m8 }, &.{ 0xa6 }, 0, .none, .none },
251 .{ .cmps, .np, &.{ .m16, .m16 }, &.{ 0xa7 }, 0, .short, .none },
252 .{ .cmps, .np, &.{ .m32, .m32 }, &.{ 0xa7 }, 0, .none, .none },
253 .{ .cmps, .np, &.{ .m64, .m64 }, &.{ 0xa7 }, 0, .long, .none },
254
255 .{ .cmpsb, .np, &.{}, &.{ 0xa6 }, 0, .none, .none },
256 .{ .cmpsw, .np, &.{}, &.{ 0xa7 }, 0, .short, .none },
257 .{ .cmpsd, .np, &.{}, &.{ 0xa7 }, 0, .none, .none },
258 .{ .cmpsq, .np, &.{}, &.{ 0xa7 }, 0, .long, .none },
259
260 .{ .cmpxchg, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xb0 }, 0, .none, .none },
261 .{ .cmpxchg, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xb0 }, 0, .rex, .none },
262 .{ .cmpxchg, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xb1 }, 0, .short, .none },
263 .{ .cmpxchg, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xb1 }, 0, .none, .none },
264 .{ .cmpxchg, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xb1 }, 0, .long, .none },
265
266 .{ .cmpxchg8b, .m, &.{ .m64 }, &.{ 0x0f, 0xc7 }, 1, .none, .none },
267 .{ .cmpxchg16b, .m, &.{ .m128 }, &.{ 0x0f, 0xc7 }, 1, .long, .none },
268
269 .{ .div, .m, &.{ .rm8 }, &.{ 0xf6 }, 6, .none, .none },
270 .{ .div, .m, &.{ .rm8 }, &.{ 0xf6 }, 6, .rex, .none },
271 .{ .div, .m, &.{ .rm16 }, &.{ 0xf7 }, 6, .short, .none },
272 .{ .div, .m, &.{ .rm32 }, &.{ 0xf7 }, 6, .none, .none },
273 .{ .div, .m, &.{ .rm64 }, &.{ 0xf7 }, 6, .long, .none },
274
275 .{ .fisttp, .m, &.{ .m16 }, &.{ 0xdf }, 1, .none, .x87 },
276 .{ .fisttp, .m, &.{ .m32 }, &.{ 0xdb }, 1, .none, .x87 },
277 .{ .fisttp, .m, &.{ .m64 }, &.{ 0xdd }, 1, .none, .x87 },
278
279 .{ .fld, .m, &.{ .m32 }, &.{ 0xd9 }, 0, .none, .x87 },
280 .{ .fld, .m, &.{ .m64 }, &.{ 0xdd }, 0, .none, .x87 },
281 .{ .fld, .m, &.{ .m80 }, &.{ 0xdb }, 5, .none, .x87 },
282
283 .{ .idiv, .m, &.{ .rm8 }, &.{ 0xf6 }, 7, .none, .none },
284 .{ .idiv, .m, &.{ .rm8 }, &.{ 0xf6 }, 7, .rex, .none },
285 .{ .idiv, .m, &.{ .rm16 }, &.{ 0xf7 }, 7, .short, .none },
286 .{ .idiv, .m, &.{ .rm32 }, &.{ 0xf7 }, 7, .none, .none },
287 .{ .idiv, .m, &.{ .rm64 }, &.{ 0xf7 }, 7, .long, .none },
288
289 .{ .imul, .m, &.{ .rm8 }, &.{ 0xf6 }, 5, .none, .none },
290 .{ .imul, .m, &.{ .rm8 }, &.{ 0xf6 }, 5, .rex, .none },
291 .{ .imul, .m, &.{ .rm16, }, &.{ 0xf7 }, 5, .short, .none },
292 .{ .imul, .m, &.{ .rm32, }, &.{ 0xf7 }, 5, .none, .none },
293 .{ .imul, .m, &.{ .rm64, }, &.{ 0xf7 }, 5, .long, .none },
294 .{ .imul, .rm, &.{ .r16, .rm16, }, &.{ 0x0f, 0xaf }, 0, .short, .none },
295 .{ .imul, .rm, &.{ .r32, .rm32, }, &.{ 0x0f, 0xaf }, 0, .none, .none },
296 .{ .imul, .rm, &.{ .r64, .rm64, }, &.{ 0x0f, 0xaf }, 0, .long, .none },
297 .{ .imul, .rmi, &.{ .r16, .rm16, .imm8s }, &.{ 0x6b }, 0, .short, .none },
298 .{ .imul, .rmi, &.{ .r32, .rm32, .imm8s }, &.{ 0x6b }, 0, .none, .none },
299 .{ .imul, .rmi, &.{ .r64, .rm64, .imm8s }, &.{ 0x6b }, 0, .long, .none },
300 .{ .imul, .rmi, &.{ .r16, .rm16, .imm16 }, &.{ 0x69 }, 0, .short, .none },
301 .{ .imul, .rmi, &.{ .r32, .rm32, .imm32 }, &.{ 0x69 }, 0, .none, .none },
302 .{ .imul, .rmi, &.{ .r64, .rm64, .imm32 }, &.{ 0x69 }, 0, .long, .none },
303
304 .{ .int3, .np, &.{}, &.{ 0xcc }, 0, .none, .none },
305
306 .{ .ja, .d, &.{ .rel32 }, &.{ 0x0f, 0x87 }, 0, .none, .none },
307 .{ .jae, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none, .none },
308 .{ .jb, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none, .none },
309 .{ .jbe, .d, &.{ .rel32 }, &.{ 0x0f, 0x86 }, 0, .none, .none },
310 .{ .jc, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none, .none },
311 .{ .jrcxz, .d, &.{ .rel32 }, &.{ 0xe3 }, 0, .none, .none },
312 .{ .je, .d, &.{ .rel32 }, &.{ 0x0f, 0x84 }, 0, .none, .none },
313 .{ .jg, .d, &.{ .rel32 }, &.{ 0x0f, 0x8f }, 0, .none, .none },
314 .{ .jge, .d, &.{ .rel32 }, &.{ 0x0f, 0x8d }, 0, .none, .none },
315 .{ .jl, .d, &.{ .rel32 }, &.{ 0x0f, 0x8c }, 0, .none, .none },
316 .{ .jle, .d, &.{ .rel32 }, &.{ 0x0f, 0x8e }, 0, .none, .none },
317 .{ .jna, .d, &.{ .rel32 }, &.{ 0x0f, 0x86 }, 0, .none, .none },
318 .{ .jnae, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none, .none },
319 .{ .jnb, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none, .none },
320 .{ .jnbe, .d, &.{ .rel32 }, &.{ 0x0f, 0x87 }, 0, .none, .none },
321 .{ .jnc, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none, .none },
322 .{ .jne, .d, &.{ .rel32 }, &.{ 0x0f, 0x85 }, 0, .none, .none },
323 .{ .jng, .d, &.{ .rel32 }, &.{ 0x0f, 0x8e }, 0, .none, .none },
324 .{ .jnge, .d, &.{ .rel32 }, &.{ 0x0f, 0x8c }, 0, .none, .none },
325 .{ .jnl, .d, &.{ .rel32 }, &.{ 0x0f, 0x8d }, 0, .none, .none },
326 .{ .jnle, .d, &.{ .rel32 }, &.{ 0x0f, 0x8f }, 0, .none, .none },
327 .{ .jno, .d, &.{ .rel32 }, &.{ 0x0f, 0x81 }, 0, .none, .none },
328 .{ .jnp, .d, &.{ .rel32 }, &.{ 0x0f, 0x8b }, 0, .none, .none },
329 .{ .jns, .d, &.{ .rel32 }, &.{ 0x0f, 0x89 }, 0, .none, .none },
330 .{ .jnz, .d, &.{ .rel32 }, &.{ 0x0f, 0x85 }, 0, .none, .none },
331 .{ .jo, .d, &.{ .rel32 }, &.{ 0x0f, 0x80 }, 0, .none, .none },
332 .{ .jp, .d, &.{ .rel32 }, &.{ 0x0f, 0x8a }, 0, .none, .none },
333 .{ .jpe, .d, &.{ .rel32 }, &.{ 0x0f, 0x8a }, 0, .none, .none },
334 .{ .jpo, .d, &.{ .rel32 }, &.{ 0x0f, 0x8b }, 0, .none, .none },
335 .{ .js, .d, &.{ .rel32 }, &.{ 0x0f, 0x88 }, 0, .none, .none },
336 .{ .jz, .d, &.{ .rel32 }, &.{ 0x0f, 0x84 }, 0, .none, .none },
337
338 .{ .jmp, .d, &.{ .rel32 }, &.{ 0xe9 }, 0, .none, .none },
339 .{ .jmp, .m, &.{ .rm64 }, &.{ 0xff }, 4, .none, .none },
340
341 .{ .lea, .rm, &.{ .r16, .m }, &.{ 0x8d }, 0, .short, .none },
342 .{ .lea, .rm, &.{ .r32, .m }, &.{ 0x8d }, 0, .none, .none },
343 .{ .lea, .rm, &.{ .r64, .m }, &.{ 0x8d }, 0, .long, .none },
344
345 .{ .lfence, .np, &.{}, &.{ 0x0f, 0xae, 0xe8 }, 0, .none, .none },
346
347 .{ .lods, .np, &.{ .m8 }, &.{ 0xac }, 0, .none, .none },
348 .{ .lods, .np, &.{ .m16 }, &.{ 0xad }, 0, .short, .none },
349 .{ .lods, .np, &.{ .m32 }, &.{ 0xad }, 0, .none, .none },
350 .{ .lods, .np, &.{ .m64 }, &.{ 0xad }, 0, .long, .none },
351
352 .{ .lodsb, .np, &.{}, &.{ 0xac }, 0, .none, .none },
353 .{ .lodsw, .np, &.{}, &.{ 0xad }, 0, .short, .none },
354 .{ .lodsd, .np, &.{}, &.{ 0xad }, 0, .none, .none },
355 .{ .lodsq, .np, &.{}, &.{ 0xad }, 0, .long, .none },
356
357 .{ .lzcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .short, .none },
358 .{ .lzcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .none, .none },
359 .{ .lzcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .long, .none },
360
361 .{ .mfence, .np, &.{}, &.{ 0x0f, 0xae, 0xf0 }, 0, .none, .none },
362
363 .{ .mov, .mr, &.{ .rm8, .r8 }, &.{ 0x88 }, 0, .none, .none },
364 .{ .mov, .mr, &.{ .rm8, .r8 }, &.{ 0x88 }, 0, .rex, .none },
365 .{ .mov, .mr, &.{ .rm16, .r16 }, &.{ 0x89 }, 0, .short, .none },
366 .{ .mov, .mr, &.{ .rm32, .r32 }, &.{ 0x89 }, 0, .none, .none },
367 .{ .mov, .mr, &.{ .rm64, .r64 }, &.{ 0x89 }, 0, .long, .none },
368 .{ .mov, .rm, &.{ .r8, .rm8 }, &.{ 0x8a }, 0, .none, .none },
369 .{ .mov, .rm, &.{ .r8, .rm8 }, &.{ 0x8a }, 0, .rex, .none },
370 .{ .mov, .rm, &.{ .r16, .rm16 }, &.{ 0x8b }, 0, .short, .none },
371 .{ .mov, .rm, &.{ .r32, .rm32 }, &.{ 0x8b }, 0, .none, .none },
372 .{ .mov, .rm, &.{ .r64, .rm64 }, &.{ 0x8b }, 0, .long, .none },
373 .{ .mov, .mr, &.{ .rm16, .sreg }, &.{ 0x8c }, 0, .short, .none },
374 .{ .mov, .mr, &.{ .r32_m16, .sreg }, &.{ 0x8c }, 0, .none, .none },
375 .{ .mov, .mr, &.{ .r64_m16, .sreg }, &.{ 0x8c }, 0, .long, .none },
376 .{ .mov, .rm, &.{ .sreg, .rm16 }, &.{ 0x8e }, 0, .short, .none },
377 .{ .mov, .rm, &.{ .sreg, .r32_m16 }, &.{ 0x8e }, 0, .none, .none },
378 .{ .mov, .rm, &.{ .sreg, .r64_m16 }, &.{ 0x8e }, 0, .long, .none },
379 .{ .mov, .fd, &.{ .al, .moffs }, &.{ 0xa0 }, 0, .none, .none },
380 .{ .mov, .fd, &.{ .ax, .moffs }, &.{ 0xa1 }, 0, .none, .none },
381 .{ .mov, .fd, &.{ .eax, .moffs }, &.{ 0xa1 }, 0, .none, .none },
382 .{ .mov, .fd, &.{ .rax, .moffs }, &.{ 0xa1 }, 0, .long, .none },
383 .{ .mov, .td, &.{ .moffs, .al }, &.{ 0xa2 }, 0, .none, .none },
384 .{ .mov, .td, &.{ .moffs, .ax }, &.{ 0xa3 }, 0, .none, .none },
385 .{ .mov, .td, &.{ .moffs, .eax }, &.{ 0xa3 }, 0, .none, .none },
386 .{ .mov, .td, &.{ .moffs, .rax }, &.{ 0xa3 }, 0, .long, .none },
387 .{ .mov, .oi, &.{ .r8, .imm8 }, &.{ 0xb0 }, 0, .none, .none },
388 .{ .mov, .oi, &.{ .r8, .imm8 }, &.{ 0xb0 }, 0, .rex, .none },
389 .{ .mov, .oi, &.{ .r16, .imm16 }, &.{ 0xb8 }, 0, .short, .none },
390 .{ .mov, .oi, &.{ .r32, .imm32 }, &.{ 0xb8 }, 0, .none, .none },
391 .{ .mov, .oi, &.{ .r64, .imm64 }, &.{ 0xb8 }, 0, .long, .none },
392 .{ .mov, .mi, &.{ .rm8, .imm8 }, &.{ 0xc6 }, 0, .none, .none },
393 .{ .mov, .mi, &.{ .rm8, .imm8 }, &.{ 0xc6 }, 0, .rex, .none },
394 .{ .mov, .mi, &.{ .rm16, .imm16 }, &.{ 0xc7 }, 0, .short, .none },
395 .{ .mov, .mi, &.{ .rm32, .imm32 }, &.{ 0xc7 }, 0, .none, .none },
396 .{ .mov, .mi, &.{ .rm64, .imm32s }, &.{ 0xc7 }, 0, .long, .none },
397
398 .{ .movbe, .rm, &.{ .r16, .m16 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .short, .none },
399 .{ .movbe, .rm, &.{ .r32, .m32 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .none, .none },
400 .{ .movbe, .rm, &.{ .r64, .m64 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .long, .none },
401 .{ .movbe, .mr, &.{ .m16, .r16 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .short, .none },
402 .{ .movbe, .mr, &.{ .m32, .r32 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .none, .none },
403 .{ .movbe, .mr, &.{ .m64, .r64 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .long, .none },
404
405 .{ .movs, .np, &.{ .m8, .m8 }, &.{ 0xa4 }, 0, .none, .none },
406 .{ .movs, .np, &.{ .m16, .m16 }, &.{ 0xa5 }, 0, .short, .none },
407 .{ .movs, .np, &.{ .m32, .m32 }, &.{ 0xa5 }, 0, .none, .none },
408 .{ .movs, .np, &.{ .m64, .m64 }, &.{ 0xa5 }, 0, .long, .none },
409
410 .{ .movsb, .np, &.{}, &.{ 0xa4 }, 0, .none, .none },
411 .{ .movsw, .np, &.{}, &.{ 0xa5 }, 0, .short, .none },
412 .{ .movsd, .np, &.{}, &.{ 0xa5 }, 0, .none, .none },
413 .{ .movsq, .np, &.{}, &.{ 0xa5 }, 0, .long, .none },
414
415 .{ .movsx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xbe }, 0, .short, .none },
416 .{ .movsx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xbe }, 0, .rex_short, .none },
417 .{ .movsx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xbe }, 0, .none, .none },
418 .{ .movsx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xbe }, 0, .rex, .none },
419 .{ .movsx, .rm, &.{ .r64, .rm8 }, &.{ 0x0f, 0xbe }, 0, .long, .none },
420 .{ .movsx, .rm, &.{ .r32, .rm16 }, &.{ 0x0f, 0xbf }, 0, .none, .none },
421 .{ .movsx, .rm, &.{ .r32, .rm16 }, &.{ 0x0f, 0xbf }, 0, .rex, .none },
422 .{ .movsx, .rm, &.{ .r64, .rm16 }, &.{ 0x0f, 0xbf }, 0, .long, .none },
419423
420424 // This instruction is discouraged.
421 .{ .movsxd, .rm, &.{ .r32, .rm32 }, &.{ 0x63 }, 0, .none },
422 .{ .movsxd, .rm, &.{ .r64, .rm32 }, &.{ 0x63 }, 0, .long },
423
424 .{ .movzx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .none },
425 .{ .movzx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .none },
426 .{ .movzx, .rm, &.{ .r64, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .long },
427 .{ .movzx, .rm, &.{ .r32, .rm16 }, &.{ 0x0f, 0xb7 }, 0, .none },
428 .{ .movzx, .rm, &.{ .r64, .rm16 }, &.{ 0x0f, 0xb7 }, 0, .long },
429
430 .{ .mul, .m, &.{ .rm8 }, &.{ 0xf6 }, 4, .none },
431 .{ .mul, .m, &.{ .rm8 }, &.{ 0xf6 }, 4, .rex },
432 .{ .mul, .m, &.{ .rm16 }, &.{ 0xf7 }, 4, .none },
433 .{ .mul, .m, &.{ .rm32 }, &.{ 0xf7 }, 4, .none },
434 .{ .mul, .m, &.{ .rm64 }, &.{ 0xf7 }, 4, .long },
435
436 .{ .neg, .m, &.{ .rm8 }, &.{ 0xf6 }, 3, .none },
437 .{ .neg, .m, &.{ .rm8 }, &.{ 0xf6 }, 3, .rex },
438 .{ .neg, .m, &.{ .rm16 }, &.{ 0xf7 }, 3, .none },
439 .{ .neg, .m, &.{ .rm32 }, &.{ 0xf7 }, 3, .none },
440 .{ .neg, .m, &.{ .rm64 }, &.{ 0xf7 }, 3, .long },
441
442 .{ .nop, .np, &.{}, &.{ 0x90 }, 0, .none },
443
444 .{ .not, .m, &.{ .rm8 }, &.{ 0xf6 }, 2, .none },
445 .{ .not, .m, &.{ .rm8 }, &.{ 0xf6 }, 2, .rex },
446 .{ .not, .m, &.{ .rm16 }, &.{ 0xf7 }, 2, .none },
447 .{ .not, .m, &.{ .rm32 }, &.{ 0xf7 }, 2, .none },
448 .{ .not, .m, &.{ .rm64 }, &.{ 0xf7 }, 2, .long },
449
450 .{ .@"or", .zi, &.{ .al, .imm8 }, &.{ 0x0c }, 0, .none },
451 .{ .@"or", .zi, &.{ .ax, .imm16 }, &.{ 0x0d }, 0, .none },
452 .{ .@"or", .zi, &.{ .eax, .imm32 }, &.{ 0x0d }, 0, .none },
453 .{ .@"or", .zi, &.{ .rax, .imm32s }, &.{ 0x0d }, 0, .long },
454 .{ .@"or", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 1, .none },
455 .{ .@"or", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 1, .rex },
456 .{ .@"or", .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 1, .none },
457 .{ .@"or", .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 1, .none },
458 .{ .@"or", .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 1, .long },
459 .{ .@"or", .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 1, .none },
460 .{ .@"or", .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 1, .none },
461 .{ .@"or", .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 1, .long },
462 .{ .@"or", .mr, &.{ .rm8, .r8 }, &.{ 0x08 }, 0, .none },
463 .{ .@"or", .mr, &.{ .rm8, .r8 }, &.{ 0x08 }, 0, .rex },
464 .{ .@"or", .mr, &.{ .rm16, .r16 }, &.{ 0x09 }, 0, .none },
465 .{ .@"or", .mr, &.{ .rm32, .r32 }, &.{ 0x09 }, 0, .none },
466 .{ .@"or", .mr, &.{ .rm64, .r64 }, &.{ 0x09 }, 0, .long },
467 .{ .@"or", .rm, &.{ .r8, .rm8 }, &.{ 0x0a }, 0, .none },
468 .{ .@"or", .rm, &.{ .r8, .rm8 }, &.{ 0x0a }, 0, .rex },
469 .{ .@"or", .rm, &.{ .r16, .rm16 }, &.{ 0x0b }, 0, .none },
470 .{ .@"or", .rm, &.{ .r32, .rm32 }, &.{ 0x0b }, 0, .none },
471 .{ .@"or", .rm, &.{ .r64, .rm64 }, &.{ 0x0b }, 0, .long },
472
473 .{ .pop, .o, &.{ .r16 }, &.{ 0x58 }, 0, .none },
474 .{ .pop, .o, &.{ .r64 }, &.{ 0x58 }, 0, .none },
475 .{ .pop, .m, &.{ .rm16 }, &.{ 0x8f }, 0, .none },
476 .{ .pop, .m, &.{ .rm64 }, &.{ 0x8f }, 0, .none },
477
478 .{ .popcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none },
479 .{ .popcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none },
480 .{ .popcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .long },
481
482 .{ .push, .o, &.{ .r16 }, &.{ 0x50 }, 0, .none },
483 .{ .push, .o, &.{ .r64 }, &.{ 0x50 }, 0, .none },
484 .{ .push, .m, &.{ .rm16 }, &.{ 0xff }, 6, .none },
485 .{ .push, .m, &.{ .rm64 }, &.{ 0xff }, 6, .none },
486 .{ .push, .i, &.{ .imm8 }, &.{ 0x6a }, 0, .none },
487 .{ .push, .i, &.{ .imm16 }, &.{ 0x68 }, 0, .none },
488 .{ .push, .i, &.{ .imm32 }, &.{ 0x68 }, 0, .none },
489
490 .{ .ret, .np, &.{}, &.{ 0xc3 }, 0, .none },
491
492 .{ .rcl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 2, .none },
493 .{ .rcl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 2, .rex },
494 .{ .rcl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 2, .none },
495 .{ .rcl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 2, .rex },
496 .{ .rcl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 2, .none },
497 .{ .rcl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 2, .rex },
498 .{ .rcl, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 2, .none },
499 .{ .rcl, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 2, .none },
500 .{ .rcl, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 2, .none },
501 .{ .rcl, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 2, .none },
502 .{ .rcl, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 2, .long },
503 .{ .rcl, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 2, .none },
504 .{ .rcl, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 2, .long },
505 .{ .rcl, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 2, .none },
506 .{ .rcl, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 2, .long },
507
508 .{ .rcr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 3, .none },
509 .{ .rcr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 3, .rex },
510 .{ .rcr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 3, .none },
511 .{ .rcr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 3, .rex },
512 .{ .rcr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 3, .none },
513 .{ .rcr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 3, .rex },
514 .{ .rcr, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 3, .none },
515 .{ .rcr, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 3, .none },
516 .{ .rcr, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 3, .none },
517 .{ .rcr, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 3, .none },
518 .{ .rcr, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 3, .long },
519 .{ .rcr, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 3, .none },
520 .{ .rcr, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 3, .long },
521 .{ .rcr, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 3, .none },
522 .{ .rcr, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 3, .long },
523
524 .{ .rol, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 0, .none },
525 .{ .rol, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 0, .rex },
526 .{ .rol, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 0, .none },
527 .{ .rol, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 0, .rex },
528 .{ .rol, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 0, .none },
529 .{ .rol, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 0, .rex },
530 .{ .rol, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 0, .none },
531 .{ .rol, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 0, .none },
532 .{ .rol, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 0, .none },
533 .{ .rol, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 0, .none },
534 .{ .rol, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 0, .long },
535 .{ .rol, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 0, .none },
536 .{ .rol, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 0, .long },
537 .{ .rol, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 0, .none },
538 .{ .rol, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 0, .long },
539
540 .{ .ror, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 1, .none },
541 .{ .ror, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 1, .rex },
542 .{ .ror, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 1, .none },
543 .{ .ror, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 1, .rex },
544 .{ .ror, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 1, .none },
545 .{ .ror, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 1, .rex },
546 .{ .ror, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 1, .none },
547 .{ .ror, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 1, .none },
548 .{ .ror, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 1, .none },
549 .{ .ror, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 1, .none },
550 .{ .ror, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 1, .long },
551 .{ .ror, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 1, .none },
552 .{ .ror, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 1, .long },
553 .{ .ror, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 1, .none },
554 .{ .ror, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 1, .long },
555
556 .{ .sal, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .none },
557 .{ .sal, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .rex },
558 .{ .sal, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 4, .none },
559 .{ .sal, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 4, .none },
560 .{ .sal, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 4, .long },
561 .{ .sal, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .none },
562 .{ .sal, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .rex },
563 .{ .sal, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 4, .none },
564 .{ .sal, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 4, .none },
565 .{ .sal, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 4, .long },
566 .{ .sal, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .none },
567 .{ .sal, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .rex },
568 .{ .sal, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 4, .none },
569 .{ .sal, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 4, .none },
570 .{ .sal, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 4, .long },
571
572 .{ .sar, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 7, .none },
573 .{ .sar, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 7, .rex },
574 .{ .sar, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 7, .none },
575 .{ .sar, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 7, .none },
576 .{ .sar, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 7, .long },
577 .{ .sar, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 7, .none },
578 .{ .sar, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 7, .rex },
579 .{ .sar, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 7, .none },
580 .{ .sar, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 7, .none },
581 .{ .sar, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 7, .long },
582 .{ .sar, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 7, .none },
583 .{ .sar, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 7, .rex },
584 .{ .sar, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 7, .none },
585 .{ .sar, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 7, .none },
586 .{ .sar, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 7, .long },
587
588 .{ .sbb, .zi, &.{ .al, .imm8 }, &.{ 0x1c }, 0, .none },
589 .{ .sbb, .zi, &.{ .ax, .imm16 }, &.{ 0x1d }, 0, .none },
590 .{ .sbb, .zi, &.{ .eax, .imm32 }, &.{ 0x1d }, 0, .none },
591 .{ .sbb, .zi, &.{ .rax, .imm32s }, &.{ 0x1d }, 0, .long },
592 .{ .sbb, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 3, .none },
593 .{ .sbb, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 3, .rex },
594 .{ .sbb, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 3, .none },
595 .{ .sbb, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 3, .none },
596 .{ .sbb, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 3, .long },
597 .{ .sbb, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 3, .none },
598 .{ .sbb, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 3, .none },
599 .{ .sbb, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 3, .long },
600 .{ .sbb, .mr, &.{ .rm8, .r8 }, &.{ 0x18 }, 0, .none },
601 .{ .sbb, .mr, &.{ .rm8, .r8 }, &.{ 0x18 }, 0, .rex },
602 .{ .sbb, .mr, &.{ .rm16, .r16 }, &.{ 0x19 }, 0, .none },
603 .{ .sbb, .mr, &.{ .rm32, .r32 }, &.{ 0x19 }, 0, .none },
604 .{ .sbb, .mr, &.{ .rm64, .r64 }, &.{ 0x19 }, 0, .long },
605 .{ .sbb, .rm, &.{ .r8, .rm8 }, &.{ 0x1a }, 0, .none },
606 .{ .sbb, .rm, &.{ .r8, .rm8 }, &.{ 0x1a }, 0, .rex },
607 .{ .sbb, .rm, &.{ .r16, .rm16 }, &.{ 0x1b }, 0, .none },
608 .{ .sbb, .rm, &.{ .r32, .rm32 }, &.{ 0x1b }, 0, .none },
609 .{ .sbb, .rm, &.{ .r64, .rm64 }, &.{ 0x1b }, 0, .long },
610
611 .{ .scas, .np, &.{ .m8 }, &.{ 0xae }, 0, .none },
612 .{ .scas, .np, &.{ .m16 }, &.{ 0xaf }, 0, .none },
613 .{ .scas, .np, &.{ .m32 }, &.{ 0xaf }, 0, .none },
614 .{ .scas, .np, &.{ .m64 }, &.{ 0xaf }, 0, .long },
615
616 .{ .scasb, .np, &.{}, &.{ 0xae }, 0, .none },
617 .{ .scasw, .np, &.{}, &.{ 0xaf }, 0, .short },
618 .{ .scasd, .np, &.{}, &.{ 0xaf }, 0, .none },
619 .{ .scasq, .np, &.{}, &.{ 0xaf }, 0, .long },
620
621 .{ .seta, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .none },
622 .{ .seta, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .rex },
623 .{ .setae, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none },
624 .{ .setae, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex },
625 .{ .setb, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none },
626 .{ .setb, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex },
627 .{ .setbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .none },
628 .{ .setbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .rex },
629 .{ .setc, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none },
630 .{ .setc, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex },
631 .{ .sete, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .none },
632 .{ .sete, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .rex },
633 .{ .setg, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .none },
634 .{ .setg, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .rex },
635 .{ .setge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .none },
636 .{ .setge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .rex },
637 .{ .setl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .none },
638 .{ .setl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .rex },
639 .{ .setle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .none },
640 .{ .setle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .rex },
641 .{ .setna, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .none },
642 .{ .setna, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .rex },
643 .{ .setnae, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none },
644 .{ .setnae, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex },
645 .{ .setnb, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none },
646 .{ .setnb, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex },
647 .{ .setnbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .none },
648 .{ .setnbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .rex },
649 .{ .setnc, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none },
650 .{ .setnc, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex },
651 .{ .setne, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .none },
652 .{ .setne, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .rex },
653 .{ .setng, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .none },
654 .{ .setng, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .rex },
655 .{ .setnge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .none },
656 .{ .setnge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .rex },
657 .{ .setnl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .none },
658 .{ .setnl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .rex },
659 .{ .setnle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .none },
660 .{ .setnle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .rex },
661 .{ .setno, .m, &.{ .rm8 }, &.{ 0x0f, 0x91 }, 0, .none },
662 .{ .setno, .m, &.{ .rm8 }, &.{ 0x0f, 0x91 }, 0, .rex },
663 .{ .setnp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .none },
664 .{ .setnp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .rex },
665 .{ .setns, .m, &.{ .rm8 }, &.{ 0x0f, 0x99 }, 0, .none },
666 .{ .setns, .m, &.{ .rm8 }, &.{ 0x0f, 0x99 }, 0, .rex },
667 .{ .setnz, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .none },
668 .{ .setnz, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .rex },
669 .{ .seto, .m, &.{ .rm8 }, &.{ 0x0f, 0x90 }, 0, .none },
670 .{ .seto, .m, &.{ .rm8 }, &.{ 0x0f, 0x90 }, 0, .rex },
671 .{ .setp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .none },
672 .{ .setp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .rex },
673 .{ .setpe, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .none },
674 .{ .setpe, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .rex },
675 .{ .setpo, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .none },
676 .{ .setpo, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .rex },
677 .{ .sets, .m, &.{ .rm8 }, &.{ 0x0f, 0x98 }, 0, .none },
678 .{ .sets, .m, &.{ .rm8 }, &.{ 0x0f, 0x98 }, 0, .rex },
679 .{ .setz, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .none },
680 .{ .setz, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .rex },
681
682 .{ .sfence, .np, &.{}, &.{ 0x0f, 0xae, 0xf8 }, 0, .none },
683
684 .{ .shl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .none },
685 .{ .shl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .rex },
686 .{ .shl, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 4, .none },
687 .{ .shl, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 4, .none },
688 .{ .shl, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 4, .long },
689 .{ .shl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .none },
690 .{ .shl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .rex },
691 .{ .shl, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 4, .none },
692 .{ .shl, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 4, .none },
693 .{ .shl, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 4, .long },
694 .{ .shl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .none },
695 .{ .shl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .rex },
696 .{ .shl, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 4, .none },
697 .{ .shl, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 4, .none },
698 .{ .shl, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 4, .long },
699
700 .{ .shld, .mri, &.{ .rm16, .r16, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .none },
701 .{ .shld, .mrc, &.{ .rm16, .r16, .cl }, &.{ 0x0f, 0xa5 }, 0, .none },
702 .{ .shld, .mri, &.{ .rm32, .r32, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .none },
703 .{ .shld, .mri, &.{ .rm64, .r64, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .long },
704 .{ .shld, .mrc, &.{ .rm32, .r32, .cl }, &.{ 0x0f, 0xa5 }, 0, .none },
705 .{ .shld, .mrc, &.{ .rm64, .r64, .cl }, &.{ 0x0f, 0xa5 }, 0, .long },
706
707 .{ .shr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 5, .none },
708 .{ .shr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 5, .rex },
709 .{ .shr, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 5, .none },
710 .{ .shr, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 5, .none },
711 .{ .shr, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 5, .long },
712 .{ .shr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 5, .none },
713 .{ .shr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 5, .rex },
714 .{ .shr, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 5, .none },
715 .{ .shr, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 5, .none },
716 .{ .shr, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 5, .long },
717 .{ .shr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 5, .none },
718 .{ .shr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 5, .rex },
719 .{ .shr, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 5, .none },
720 .{ .shr, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 5, .none },
721 .{ .shr, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 5, .long },
722
723 .{ .shrd, .mri, &.{ .rm16, .r16, .imm8 }, &.{ 0x0f, 0xac }, 0, .none },
724 .{ .shrd, .mrc, &.{ .rm16, .r16, .cl }, &.{ 0x0f, 0xad }, 0, .none },
725 .{ .shrd, .mri, &.{ .rm32, .r32, .imm8 }, &.{ 0x0f, 0xac }, 0, .none },
726 .{ .shrd, .mri, &.{ .rm64, .r64, .imm8 }, &.{ 0x0f, 0xac }, 0, .long },
727 .{ .shrd, .mrc, &.{ .rm32, .r32, .cl }, &.{ 0x0f, 0xad }, 0, .none },
728 .{ .shrd, .mrc, &.{ .rm64, .r64, .cl }, &.{ 0x0f, 0xad }, 0, .long },
729
730 .{ .stos, .np, &.{ .m8 }, &.{ 0xaa }, 0, .none },
731 .{ .stos, .np, &.{ .m16 }, &.{ 0xab }, 0, .none },
732 .{ .stos, .np, &.{ .m32 }, &.{ 0xab }, 0, .none },
733 .{ .stos, .np, &.{ .m64 }, &.{ 0xab }, 0, .long },
734
735 .{ .stosb, .np, &.{}, &.{ 0xaa }, 0, .none },
736 .{ .stosw, .np, &.{}, &.{ 0xab }, 0, .short },
737 .{ .stosd, .np, &.{}, &.{ 0xab }, 0, .none },
738 .{ .stosq, .np, &.{}, &.{ 0xab }, 0, .long },
739
740 .{ .sub, .zi, &.{ .al, .imm8 }, &.{ 0x2c }, 0, .none },
741 .{ .sub, .zi, &.{ .ax, .imm16 }, &.{ 0x2d }, 0, .none },
742 .{ .sub, .zi, &.{ .eax, .imm32 }, &.{ 0x2d }, 0, .none },
743 .{ .sub, .zi, &.{ .rax, .imm32s }, &.{ 0x2d }, 0, .long },
744 .{ .sub, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 5, .none },
745 .{ .sub, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 5, .rex },
746 .{ .sub, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 5, .none },
747 .{ .sub, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 5, .none },
748 .{ .sub, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 5, .long },
749 .{ .sub, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 5, .none },
750 .{ .sub, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 5, .none },
751 .{ .sub, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 5, .long },
752 .{ .sub, .mr, &.{ .rm8, .r8 }, &.{ 0x28 }, 0, .none },
753 .{ .sub, .mr, &.{ .rm8, .r8 }, &.{ 0x28 }, 0, .rex },
754 .{ .sub, .mr, &.{ .rm16, .r16 }, &.{ 0x29 }, 0, .none },
755 .{ .sub, .mr, &.{ .rm32, .r32 }, &.{ 0x29 }, 0, .none },
756 .{ .sub, .mr, &.{ .rm64, .r64 }, &.{ 0x29 }, 0, .long },
757 .{ .sub, .rm, &.{ .r8, .rm8 }, &.{ 0x2a }, 0, .none },
758 .{ .sub, .rm, &.{ .r8, .rm8 }, &.{ 0x2a }, 0, .rex },
759 .{ .sub, .rm, &.{ .r16, .rm16 }, &.{ 0x2b }, 0, .none },
760 .{ .sub, .rm, &.{ .r32, .rm32 }, &.{ 0x2b }, 0, .none },
761 .{ .sub, .rm, &.{ .r64, .rm64 }, &.{ 0x2b }, 0, .long },
762
763 .{ .syscall, .np, &.{}, &.{ 0x0f, 0x05 }, 0, .none }
764,
765 .{ .@"test", .zi, &.{ .al, .imm8 }, &.{ 0xa8 }, 0, .none },
766 .{ .@"test", .zi, &.{ .ax, .imm16 }, &.{ 0xa9 }, 0, .none },
767 .{ .@"test", .zi, &.{ .eax, .imm32 }, &.{ 0xa9 }, 0, .none },
768 .{ .@"test", .zi, &.{ .rax, .imm32s }, &.{ 0xa9 }, 0, .long },
769 .{ .@"test", .mi, &.{ .rm8, .imm8 }, &.{ 0xf6 }, 0, .none },
770 .{ .@"test", .mi, &.{ .rm8, .imm8 }, &.{ 0xf6 }, 0, .rex },
771 .{ .@"test", .mi, &.{ .rm16, .imm16 }, &.{ 0xf7 }, 0, .none },
772 .{ .@"test", .mi, &.{ .rm32, .imm32 }, &.{ 0xf7 }, 0, .none },
773 .{ .@"test", .mi, &.{ .rm64, .imm32s }, &.{ 0xf7 }, 0, .long },
774 .{ .@"test", .mr, &.{ .rm8, .r8 }, &.{ 0x84 }, 0, .none },
775 .{ .@"test", .mr, &.{ .rm8, .r8 }, &.{ 0x84 }, 0, .rex },
776 .{ .@"test", .mr, &.{ .rm16, .r16 }, &.{ 0x85 }, 0, .none },
777 .{ .@"test", .mr, &.{ .rm32, .r32 }, &.{ 0x85 }, 0, .none },
778 .{ .@"test", .mr, &.{ .rm64, .r64 }, &.{ 0x85 }, 0, .long },
779
780 .{ .tzcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .none },
781 .{ .tzcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .none },
782 .{ .tzcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .long },
783
784 .{ .ud2, .np, &.{}, &.{ 0x0f, 0x0b }, 0, .none },
785
786 .{ .xadd, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xc0 }, 0, .none },
787 .{ .xadd, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xc0 }, 0, .rex },
788 .{ .xadd, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xc1 }, 0, .none },
789 .{ .xadd, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xc1 }, 0, .none },
790 .{ .xadd, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xc1 }, 0, .long },
791
792 .{ .xchg, .o, &.{ .ax, .r16 }, &.{ 0x90 }, 0, .none },
793 .{ .xchg, .o, &.{ .r16, .ax }, &.{ 0x90 }, 0, .none },
794 .{ .xchg, .o, &.{ .eax, .r32 }, &.{ 0x90 }, 0, .none },
795 .{ .xchg, .o, &.{ .rax, .r64 }, &.{ 0x90 }, 0, .long },
796 .{ .xchg, .o, &.{ .r32, .eax }, &.{ 0x90 }, 0, .none },
797 .{ .xchg, .o, &.{ .r64, .rax }, &.{ 0x90 }, 0, .long },
798 .{ .xchg, .mr, &.{ .rm8, .r8 }, &.{ 0x86 }, 0, .none },
799 .{ .xchg, .mr, &.{ .rm8, .r8 }, &.{ 0x86 }, 0, .rex },
800 .{ .xchg, .rm, &.{ .r8, .rm8 }, &.{ 0x86 }, 0, .none },
801 .{ .xchg, .rm, &.{ .r8, .rm8 }, &.{ 0x86 }, 0, .rex },
802 .{ .xchg, .mr, &.{ .rm16, .r16 }, &.{ 0x87 }, 0, .none },
803 .{ .xchg, .rm, &.{ .r16, .rm16 }, &.{ 0x87 }, 0, .none },
804 .{ .xchg, .mr, &.{ .rm32, .r32 }, &.{ 0x87 }, 0, .none },
805 .{ .xchg, .mr, &.{ .rm64, .r64 }, &.{ 0x87 }, 0, .long },
806 .{ .xchg, .rm, &.{ .r32, .rm32 }, &.{ 0x87 }, 0, .none },
807 .{ .xchg, .rm, &.{ .r64, .rm64 }, &.{ 0x87 }, 0, .long },
808
809 .{ .xor, .zi, &.{ .al, .imm8 }, &.{ 0x34 }, 0, .none },
810 .{ .xor, .zi, &.{ .ax, .imm16 }, &.{ 0x35 }, 0, .none },
811 .{ .xor, .zi, &.{ .eax, .imm32 }, &.{ 0x35 }, 0, .none },
812 .{ .xor, .zi, &.{ .rax, .imm32s }, &.{ 0x35 }, 0, .long },
813 .{ .xor, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 6, .none },
814 .{ .xor, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 6, .rex },
815 .{ .xor, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 6, .none },
816 .{ .xor, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 6, .none },
817 .{ .xor, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 6, .long },
818 .{ .xor, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 6, .none },
819 .{ .xor, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 6, .none },
820 .{ .xor, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 6, .long },
821 .{ .xor, .mr, &.{ .rm8, .r8 }, &.{ 0x30 }, 0, .none },
822 .{ .xor, .mr, &.{ .rm8, .r8 }, &.{ 0x30 }, 0, .rex },
823 .{ .xor, .mr, &.{ .rm16, .r16 }, &.{ 0x31 }, 0, .none },
824 .{ .xor, .mr, &.{ .rm32, .r32 }, &.{ 0x31 }, 0, .none },
825 .{ .xor, .mr, &.{ .rm64, .r64 }, &.{ 0x31 }, 0, .long },
826 .{ .xor, .rm, &.{ .r8, .rm8 }, &.{ 0x32 }, 0, .none },
827 .{ .xor, .rm, &.{ .r8, .rm8 }, &.{ 0x32 }, 0, .rex },
828 .{ .xor, .rm, &.{ .r16, .rm16 }, &.{ 0x33 }, 0, .none },
829 .{ .xor, .rm, &.{ .r32, .rm32 }, &.{ 0x33 }, 0, .none },
830 .{ .xor, .rm, &.{ .r64, .rm64 }, &.{ 0x33 }, 0, .long },
425 .{ .movsxd, .rm, &.{ .r32, .rm32 }, &.{ 0x63 }, 0, .none, .none },
426 .{ .movsxd, .rm, &.{ .r64, .rm32 }, &.{ 0x63 }, 0, .long, .none },
427
428 .{ .movzx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .short, .none },
429 .{ .movzx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .rex_short, .none },
430 .{ .movzx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .none, .none },
431 .{ .movzx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .rex, .none },
432 .{ .movzx, .rm, &.{ .r64, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .long, .none },
433 .{ .movzx, .rm, &.{ .r32, .rm16 }, &.{ 0x0f, 0xb7 }, 0, .none, .none },
434 .{ .movzx, .rm, &.{ .r32, .rm16 }, &.{ 0x0f, 0xb7 }, 0, .rex, .none },
435 .{ .movzx, .rm, &.{ .r64, .rm16 }, &.{ 0x0f, 0xb7 }, 0, .long, .none },
436
437 .{ .mul, .m, &.{ .rm8 }, &.{ 0xf6 }, 4, .none, .none },
438 .{ .mul, .m, &.{ .rm8 }, &.{ 0xf6 }, 4, .rex, .none },
439 .{ .mul, .m, &.{ .rm16 }, &.{ 0xf7 }, 4, .short, .none },
440 .{ .mul, .m, &.{ .rm32 }, &.{ 0xf7 }, 4, .none, .none },
441 .{ .mul, .m, &.{ .rm64 }, &.{ 0xf7 }, 4, .long, .none },
442
443 .{ .neg, .m, &.{ .rm8 }, &.{ 0xf6 }, 3, .none, .none },
444 .{ .neg, .m, &.{ .rm8 }, &.{ 0xf6 }, 3, .rex, .none },
445 .{ .neg, .m, &.{ .rm16 }, &.{ 0xf7 }, 3, .short, .none },
446 .{ .neg, .m, &.{ .rm32 }, &.{ 0xf7 }, 3, .none, .none },
447 .{ .neg, .m, &.{ .rm64 }, &.{ 0xf7 }, 3, .long, .none },
448
449 .{ .nop, .np, &.{}, &.{ 0x90 }, 0, .none, .none },
450
451 .{ .not, .m, &.{ .rm8 }, &.{ 0xf6 }, 2, .none, .none },
452 .{ .not, .m, &.{ .rm8 }, &.{ 0xf6 }, 2, .rex, .none },
453 .{ .not, .m, &.{ .rm16 }, &.{ 0xf7 }, 2, .short, .none },
454 .{ .not, .m, &.{ .rm32 }, &.{ 0xf7 }, 2, .none, .none },
455 .{ .not, .m, &.{ .rm64 }, &.{ 0xf7 }, 2, .long, .none },
456
457 .{ .@"or", .zi, &.{ .al, .imm8 }, &.{ 0x0c }, 0, .none, .none },
458 .{ .@"or", .zi, &.{ .ax, .imm16 }, &.{ 0x0d }, 0, .short, .none },
459 .{ .@"or", .zi, &.{ .eax, .imm32 }, &.{ 0x0d }, 0, .none, .none },
460 .{ .@"or", .zi, &.{ .rax, .imm32s }, &.{ 0x0d }, 0, .long, .none },
461 .{ .@"or", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 1, .none, .none },
462 .{ .@"or", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 1, .rex, .none },
463 .{ .@"or", .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 1, .short, .none },
464 .{ .@"or", .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 1, .none, .none },
465 .{ .@"or", .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 1, .long, .none },
466 .{ .@"or", .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 1, .short, .none },
467 .{ .@"or", .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 1, .none, .none },
468 .{ .@"or", .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 1, .long, .none },
469 .{ .@"or", .mr, &.{ .rm8, .r8 }, &.{ 0x08 }, 0, .none, .none },
470 .{ .@"or", .mr, &.{ .rm8, .r8 }, &.{ 0x08 }, 0, .rex, .none },
471 .{ .@"or", .mr, &.{ .rm16, .r16 }, &.{ 0x09 }, 0, .short, .none },
472 .{ .@"or", .mr, &.{ .rm32, .r32 }, &.{ 0x09 }, 0, .none, .none },
473 .{ .@"or", .mr, &.{ .rm64, .r64 }, &.{ 0x09 }, 0, .long, .none },
474 .{ .@"or", .rm, &.{ .r8, .rm8 }, &.{ 0x0a }, 0, .none, .none },
475 .{ .@"or", .rm, &.{ .r8, .rm8 }, &.{ 0x0a }, 0, .rex, .none },
476 .{ .@"or", .rm, &.{ .r16, .rm16 }, &.{ 0x0b }, 0, .short, .none },
477 .{ .@"or", .rm, &.{ .r32, .rm32 }, &.{ 0x0b }, 0, .none, .none },
478 .{ .@"or", .rm, &.{ .r64, .rm64 }, &.{ 0x0b }, 0, .long, .none },
479
480 .{ .pop, .o, &.{ .r16 }, &.{ 0x58 }, 0, .short, .none },
481 .{ .pop, .o, &.{ .r64 }, &.{ 0x58 }, 0, .none, .none },
482 .{ .pop, .m, &.{ .rm16 }, &.{ 0x8f }, 0, .short, .none },
483 .{ .pop, .m, &.{ .rm64 }, &.{ 0x8f }, 0, .none, .none },
484
485 .{ .popcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .short, .none },
486 .{ .popcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none, .none },
487 .{ .popcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .long, .none },
488
489 .{ .push, .o, &.{ .r16 }, &.{ 0x50 }, 0, .short, .none },
490 .{ .push, .o, &.{ .r64 }, &.{ 0x50 }, 0, .none, .none },
491 .{ .push, .m, &.{ .rm16 }, &.{ 0xff }, 6, .short, .none },
492 .{ .push, .m, &.{ .rm64 }, &.{ 0xff }, 6, .none, .none },
493 .{ .push, .i, &.{ .imm8 }, &.{ 0x6a }, 0, .none, .none },
494 .{ .push, .i, &.{ .imm16 }, &.{ 0x68 }, 0, .short, .none },
495 .{ .push, .i, &.{ .imm32 }, &.{ 0x68 }, 0, .none, .none },
496
497 .{ .ret, .np, &.{}, &.{ 0xc3 }, 0, .none, .none },
498
499 .{ .rcl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 2, .none, .none },
500 .{ .rcl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 2, .rex, .none },
501 .{ .rcl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 2, .none, .none },
502 .{ .rcl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 2, .rex, .none },
503 .{ .rcl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 2, .none, .none },
504 .{ .rcl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 2, .rex, .none },
505 .{ .rcl, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 2, .short, .none },
506 .{ .rcl, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 2, .short, .none },
507 .{ .rcl, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 2, .short, .none },
508 .{ .rcl, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 2, .none, .none },
509 .{ .rcl, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 2, .long, .none },
510 .{ .rcl, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 2, .none, .none },
511 .{ .rcl, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 2, .long, .none },
512 .{ .rcl, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 2, .none, .none },
513 .{ .rcl, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 2, .long, .none },
514
515 .{ .rcr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 3, .none, .none },
516 .{ .rcr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 3, .rex, .none },
517 .{ .rcr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 3, .none, .none },
518 .{ .rcr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 3, .rex, .none },
519 .{ .rcr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 3, .none, .none },
520 .{ .rcr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 3, .rex, .none },
521 .{ .rcr, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 3, .short, .none },
522 .{ .rcr, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 3, .short, .none },
523 .{ .rcr, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 3, .short, .none },
524 .{ .rcr, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 3, .none, .none },
525 .{ .rcr, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 3, .long, .none },
526 .{ .rcr, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 3, .none, .none },
527 .{ .rcr, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 3, .long, .none },
528 .{ .rcr, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 3, .none, .none },
529 .{ .rcr, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 3, .long, .none },
530
531 .{ .rol, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 0, .none, .none },
532 .{ .rol, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 0, .rex, .none },
533 .{ .rol, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 0, .none, .none },
534 .{ .rol, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 0, .rex, .none },
535 .{ .rol, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 0, .none, .none },
536 .{ .rol, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 0, .rex, .none },
537 .{ .rol, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 0, .short, .none },
538 .{ .rol, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 0, .short, .none },
539 .{ .rol, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 0, .short, .none },
540 .{ .rol, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 0, .none, .none },
541 .{ .rol, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 0, .long, .none },
542 .{ .rol, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 0, .none, .none },
543 .{ .rol, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 0, .long, .none },
544 .{ .rol, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 0, .none, .none },
545 .{ .rol, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 0, .long, .none },
546
547 .{ .ror, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 1, .none, .none },
548 .{ .ror, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 1, .rex, .none },
549 .{ .ror, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 1, .none, .none },
550 .{ .ror, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 1, .rex, .none },
551 .{ .ror, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 1, .none, .none },
552 .{ .ror, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 1, .rex, .none },
553 .{ .ror, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 1, .short, .none },
554 .{ .ror, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 1, .short, .none },
555 .{ .ror, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 1, .short, .none },
556 .{ .ror, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 1, .none, .none },
557 .{ .ror, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 1, .long, .none },
558 .{ .ror, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 1, .none, .none },
559 .{ .ror, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 1, .long, .none },
560 .{ .ror, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 1, .none, .none },
561 .{ .ror, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 1, .long, .none },
562
563 .{ .sal, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .none, .none },
564 .{ .sal, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .rex, .none },
565 .{ .sal, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 4, .short, .none },
566 .{ .sal, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 4, .none, .none },
567 .{ .sal, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 4, .long, .none },
568 .{ .sal, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .none, .none },
569 .{ .sal, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .rex, .none },
570 .{ .sal, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 4, .short, .none },
571 .{ .sal, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 4, .none, .none },
572 .{ .sal, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 4, .long, .none },
573 .{ .sal, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .none, .none },
574 .{ .sal, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .rex, .none },
575 .{ .sal, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 4, .short, .none },
576 .{ .sal, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 4, .none, .none },
577 .{ .sal, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 4, .long, .none },
578
579 .{ .sar, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 7, .none, .none },
580 .{ .sar, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 7, .rex, .none },
581 .{ .sar, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 7, .short, .none },
582 .{ .sar, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 7, .none, .none },
583 .{ .sar, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 7, .long, .none },
584 .{ .sar, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 7, .none, .none },
585 .{ .sar, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 7, .rex, .none },
586 .{ .sar, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 7, .short, .none },
587 .{ .sar, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 7, .none, .none },
588 .{ .sar, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 7, .long, .none },
589 .{ .sar, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 7, .none, .none },
590 .{ .sar, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 7, .rex, .none },
591 .{ .sar, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 7, .short, .none },
592 .{ .sar, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 7, .none, .none },
593 .{ .sar, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 7, .long, .none },
594
595 .{ .sbb, .zi, &.{ .al, .imm8 }, &.{ 0x1c }, 0, .none, .none },
596 .{ .sbb, .zi, &.{ .ax, .imm16 }, &.{ 0x1d }, 0, .short, .none },
597 .{ .sbb, .zi, &.{ .eax, .imm32 }, &.{ 0x1d }, 0, .none, .none },
598 .{ .sbb, .zi, &.{ .rax, .imm32s }, &.{ 0x1d }, 0, .long, .none },
599 .{ .sbb, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 3, .none, .none },
600 .{ .sbb, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 3, .rex, .none },
601 .{ .sbb, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 3, .short, .none },
602 .{ .sbb, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 3, .none, .none },
603 .{ .sbb, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 3, .long, .none },
604 .{ .sbb, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 3, .short, .none },
605 .{ .sbb, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 3, .none, .none },
606 .{ .sbb, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 3, .long, .none },
607 .{ .sbb, .mr, &.{ .rm8, .r8 }, &.{ 0x18 }, 0, .none, .none },
608 .{ .sbb, .mr, &.{ .rm8, .r8 }, &.{ 0x18 }, 0, .rex, .none },
609 .{ .sbb, .mr, &.{ .rm16, .r16 }, &.{ 0x19 }, 0, .short, .none },
610 .{ .sbb, .mr, &.{ .rm32, .r32 }, &.{ 0x19 }, 0, .none, .none },
611 .{ .sbb, .mr, &.{ .rm64, .r64 }, &.{ 0x19 }, 0, .long, .none },
612 .{ .sbb, .rm, &.{ .r8, .rm8 }, &.{ 0x1a }, 0, .none, .none },
613 .{ .sbb, .rm, &.{ .r8, .rm8 }, &.{ 0x1a }, 0, .rex, .none },
614 .{ .sbb, .rm, &.{ .r16, .rm16 }, &.{ 0x1b }, 0, .short, .none },
615 .{ .sbb, .rm, &.{ .r32, .rm32 }, &.{ 0x1b }, 0, .none, .none },
616 .{ .sbb, .rm, &.{ .r64, .rm64 }, &.{ 0x1b }, 0, .long, .none },
617
618 .{ .scas, .np, &.{ .m8 }, &.{ 0xae }, 0, .none, .none },
619 .{ .scas, .np, &.{ .m16 }, &.{ 0xaf }, 0, .short, .none },
620 .{ .scas, .np, &.{ .m32 }, &.{ 0xaf }, 0, .none, .none },
621 .{ .scas, .np, &.{ .m64 }, &.{ 0xaf }, 0, .long, .none },
622
623 .{ .scasb, .np, &.{}, &.{ 0xae }, 0, .none, .none },
624 .{ .scasw, .np, &.{}, &.{ 0xaf }, 0, .short, .none },
625 .{ .scasd, .np, &.{}, &.{ 0xaf }, 0, .none, .none },
626 .{ .scasq, .np, &.{}, &.{ 0xaf }, 0, .long, .none },
627
628 .{ .seta, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .none, .none },
629 .{ .seta, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .rex, .none },
630 .{ .setae, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none, .none },
631 .{ .setae, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex, .none },
632 .{ .setb, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none, .none },
633 .{ .setb, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex, .none },
634 .{ .setbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .none, .none },
635 .{ .setbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .rex, .none },
636 .{ .setc, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none, .none },
637 .{ .setc, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex, .none },
638 .{ .sete, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .none, .none },
639 .{ .sete, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .rex, .none },
640 .{ .setg, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .none, .none },
641 .{ .setg, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .rex, .none },
642 .{ .setge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .none, .none },
643 .{ .setge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .rex, .none },
644 .{ .setl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .none, .none },
645 .{ .setl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .rex, .none },
646 .{ .setle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .none, .none },
647 .{ .setle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .rex, .none },
648 .{ .setna, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .none, .none },
649 .{ .setna, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .rex, .none },
650 .{ .setnae, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none, .none },
651 .{ .setnae, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex, .none },
652 .{ .setnb, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none, .none },
653 .{ .setnb, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex, .none },
654 .{ .setnbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .none, .none },
655 .{ .setnbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .rex, .none },
656 .{ .setnc, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none, .none },
657 .{ .setnc, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex, .none },
658 .{ .setne, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .none, .none },
659 .{ .setne, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .rex, .none },
660 .{ .setng, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .none, .none },
661 .{ .setng, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .rex, .none },
662 .{ .setnge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .none, .none },
663 .{ .setnge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .rex, .none },
664 .{ .setnl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .none, .none },
665 .{ .setnl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .rex, .none },
666 .{ .setnle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .none, .none },
667 .{ .setnle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .rex, .none },
668 .{ .setno, .m, &.{ .rm8 }, &.{ 0x0f, 0x91 }, 0, .none, .none },
669 .{ .setno, .m, &.{ .rm8 }, &.{ 0x0f, 0x91 }, 0, .rex, .none },
670 .{ .setnp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .none, .none },
671 .{ .setnp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .rex, .none },
672 .{ .setns, .m, &.{ .rm8 }, &.{ 0x0f, 0x99 }, 0, .none, .none },
673 .{ .setns, .m, &.{ .rm8 }, &.{ 0x0f, 0x99 }, 0, .rex, .none },
674 .{ .setnz, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .none, .none },
675 .{ .setnz, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .rex, .none },
676 .{ .seto, .m, &.{ .rm8 }, &.{ 0x0f, 0x90 }, 0, .none, .none },
677 .{ .seto, .m, &.{ .rm8 }, &.{ 0x0f, 0x90 }, 0, .rex, .none },
678 .{ .setp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .none, .none },
679 .{ .setp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .rex, .none },
680 .{ .setpe, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .none, .none },
681 .{ .setpe, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .rex, .none },
682 .{ .setpo, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .none, .none },
683 .{ .setpo, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .rex, .none },
684 .{ .sets, .m, &.{ .rm8 }, &.{ 0x0f, 0x98 }, 0, .none, .none },
685 .{ .sets, .m, &.{ .rm8 }, &.{ 0x0f, 0x98 }, 0, .rex, .none },
686 .{ .setz, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .none, .none },
687 .{ .setz, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .rex, .none },
688
689 .{ .sfence, .np, &.{}, &.{ 0x0f, 0xae, 0xf8 }, 0, .none, .none },
690
691 .{ .shl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .none, .none },
692 .{ .shl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .rex, .none },
693 .{ .shl, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 4, .short, .none },
694 .{ .shl, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 4, .none, .none },
695 .{ .shl, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 4, .long, .none },
696 .{ .shl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .none, .none },
697 .{ .shl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .rex, .none },
698 .{ .shl, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 4, .short, .none },
699 .{ .shl, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 4, .none, .none },
700 .{ .shl, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 4, .long, .none },
701 .{ .shl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .none, .none },
702 .{ .shl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .rex, .none },
703 .{ .shl, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 4, .short, .none },
704 .{ .shl, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 4, .none, .none },
705 .{ .shl, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 4, .long, .none },
706
707 .{ .shld, .mri, &.{ .rm16, .r16, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .short, .none },
708 .{ .shld, .mrc, &.{ .rm16, .r16, .cl }, &.{ 0x0f, 0xa5 }, 0, .short, .none },
709 .{ .shld, .mri, &.{ .rm32, .r32, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .none, .none },
710 .{ .shld, .mri, &.{ .rm64, .r64, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .long, .none },
711 .{ .shld, .mrc, &.{ .rm32, .r32, .cl }, &.{ 0x0f, 0xa5 }, 0, .none, .none },
712 .{ .shld, .mrc, &.{ .rm64, .r64, .cl }, &.{ 0x0f, 0xa5 }, 0, .long, .none },
713
714 .{ .shr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 5, .none, .none },
715 .{ .shr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 5, .rex, .none },
716 .{ .shr, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 5, .short, .none },
717 .{ .shr, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 5, .none, .none },
718 .{ .shr, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 5, .long, .none },
719 .{ .shr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 5, .none, .none },
720 .{ .shr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 5, .rex, .none },
721 .{ .shr, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 5, .short, .none },
722 .{ .shr, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 5, .none, .none },
723 .{ .shr, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 5, .long, .none },
724 .{ .shr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 5, .none, .none },
725 .{ .shr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 5, .rex, .none },
726 .{ .shr, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 5, .short, .none },
727 .{ .shr, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 5, .none, .none },
728 .{ .shr, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 5, .long, .none },
729
730 .{ .shrd, .mri, &.{ .rm16, .r16, .imm8 }, &.{ 0x0f, 0xac }, 0, .short, .none },
731 .{ .shrd, .mrc, &.{ .rm16, .r16, .cl }, &.{ 0x0f, 0xad }, 0, .short, .none },
732 .{ .shrd, .mri, &.{ .rm32, .r32, .imm8 }, &.{ 0x0f, 0xac }, 0, .none, .none },
733 .{ .shrd, .mri, &.{ .rm64, .r64, .imm8 }, &.{ 0x0f, 0xac }, 0, .long, .none },
734 .{ .shrd, .mrc, &.{ .rm32, .r32, .cl }, &.{ 0x0f, 0xad }, 0, .none, .none },
735 .{ .shrd, .mrc, &.{ .rm64, .r64, .cl }, &.{ 0x0f, 0xad }, 0, .long, .none },
736
737 .{ .stos, .np, &.{ .m8 }, &.{ 0xaa }, 0, .none, .none },
738 .{ .stos, .np, &.{ .m16 }, &.{ 0xab }, 0, .short, .none },
739 .{ .stos, .np, &.{ .m32 }, &.{ 0xab }, 0, .none, .none },
740 .{ .stos, .np, &.{ .m64 }, &.{ 0xab }, 0, .long, .none },
741
742 .{ .stosb, .np, &.{}, &.{ 0xaa }, 0, .none, .none },
743 .{ .stosw, .np, &.{}, &.{ 0xab }, 0, .short, .none },
744 .{ .stosd, .np, &.{}, &.{ 0xab }, 0, .none, .none },
745 .{ .stosq, .np, &.{}, &.{ 0xab }, 0, .long, .none },
746
747 .{ .sub, .zi, &.{ .al, .imm8 }, &.{ 0x2c }, 0, .none, .none },
748 .{ .sub, .zi, &.{ .ax, .imm16 }, &.{ 0x2d }, 0, .short, .none },
749 .{ .sub, .zi, &.{ .eax, .imm32 }, &.{ 0x2d }, 0, .none, .none },
750 .{ .sub, .zi, &.{ .rax, .imm32s }, &.{ 0x2d }, 0, .long, .none },
751 .{ .sub, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 5, .none, .none },
752 .{ .sub, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 5, .rex, .none },
753 .{ .sub, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 5, .short, .none },
754 .{ .sub, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 5, .none, .none },
755 .{ .sub, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 5, .long, .none },
756 .{ .sub, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 5, .short, .none },
757 .{ .sub, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 5, .none, .none },
758 .{ .sub, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 5, .long, .none },
759 .{ .sub, .mr, &.{ .rm8, .r8 }, &.{ 0x28 }, 0, .none, .none },
760 .{ .sub, .mr, &.{ .rm8, .r8 }, &.{ 0x28 }, 0, .rex, .none },
761 .{ .sub, .mr, &.{ .rm16, .r16 }, &.{ 0x29 }, 0, .short, .none },
762 .{ .sub, .mr, &.{ .rm32, .r32 }, &.{ 0x29 }, 0, .none, .none },
763 .{ .sub, .mr, &.{ .rm64, .r64 }, &.{ 0x29 }, 0, .long, .none },
764 .{ .sub, .rm, &.{ .r8, .rm8 }, &.{ 0x2a }, 0, .none, .none },
765 .{ .sub, .rm, &.{ .r8, .rm8 }, &.{ 0x2a }, 0, .rex, .none },
766 .{ .sub, .rm, &.{ .r16, .rm16 }, &.{ 0x2b }, 0, .short, .none },
767 .{ .sub, .rm, &.{ .r32, .rm32 }, &.{ 0x2b }, 0, .none, .none },
768 .{ .sub, .rm, &.{ .r64, .rm64 }, &.{ 0x2b }, 0, .long, .none },
769
770 .{ .syscall, .np, &.{}, &.{ 0x0f, 0x05 }, 0, .none, .none },
771
772 .{ .@"test", .zi, &.{ .al, .imm8 }, &.{ 0xa8 }, 0, .none, .none },
773 .{ .@"test", .zi, &.{ .ax, .imm16 }, &.{ 0xa9 }, 0, .short, .none },
774 .{ .@"test", .zi, &.{ .eax, .imm32 }, &.{ 0xa9 }, 0, .none, .none },
775 .{ .@"test", .zi, &.{ .rax, .imm32s }, &.{ 0xa9 }, 0, .long, .none },
776 .{ .@"test", .mi, &.{ .rm8, .imm8 }, &.{ 0xf6 }, 0, .none, .none },
777 .{ .@"test", .mi, &.{ .rm8, .imm8 }, &.{ 0xf6 }, 0, .rex, .none },
778 .{ .@"test", .mi, &.{ .rm16, .imm16 }, &.{ 0xf7 }, 0, .short, .none },
779 .{ .@"test", .mi, &.{ .rm32, .imm32 }, &.{ 0xf7 }, 0, .none, .none },
780 .{ .@"test", .mi, &.{ .rm64, .imm32s }, &.{ 0xf7 }, 0, .long, .none },
781 .{ .@"test", .mr, &.{ .rm8, .r8 }, &.{ 0x84 }, 0, .none, .none },
782 .{ .@"test", .mr, &.{ .rm8, .r8 }, &.{ 0x84 }, 0, .rex, .none },
783 .{ .@"test", .mr, &.{ .rm16, .r16 }, &.{ 0x85 }, 0, .short, .none },
784 .{ .@"test", .mr, &.{ .rm32, .r32 }, &.{ 0x85 }, 0, .none, .none },
785 .{ .@"test", .mr, &.{ .rm64, .r64 }, &.{ 0x85 }, 0, .long, .none },
786
787 .{ .tzcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .short, .none },
788 .{ .tzcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .none, .none },
789 .{ .tzcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .long, .none },
790
791 .{ .ud2, .np, &.{}, &.{ 0x0f, 0x0b }, 0, .none, .none },
792
793 .{ .xadd, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xc0 }, 0, .none, .none },
794 .{ .xadd, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xc0 }, 0, .rex, .none },
795 .{ .xadd, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xc1 }, 0, .short, .none },
796 .{ .xadd, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xc1 }, 0, .none, .none },
797 .{ .xadd, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xc1 }, 0, .long, .none },
798
799 .{ .xchg, .o, &.{ .ax, .r16 }, &.{ 0x90 }, 0, .short, .none },
800 .{ .xchg, .o, &.{ .r16, .ax }, &.{ 0x90 }, 0, .short, .none },
801 .{ .xchg, .o, &.{ .eax, .r32 }, &.{ 0x90 }, 0, .none, .none },
802 .{ .xchg, .o, &.{ .rax, .r64 }, &.{ 0x90 }, 0, .long, .none },
803 .{ .xchg, .o, &.{ .r32, .eax }, &.{ 0x90 }, 0, .none, .none },
804 .{ .xchg, .o, &.{ .r64, .rax }, &.{ 0x90 }, 0, .long, .none },
805 .{ .xchg, .mr, &.{ .rm8, .r8 }, &.{ 0x86 }, 0, .none, .none },
806 .{ .xchg, .mr, &.{ .rm8, .r8 }, &.{ 0x86 }, 0, .rex, .none },
807 .{ .xchg, .rm, &.{ .r8, .rm8 }, &.{ 0x86 }, 0, .none, .none },
808 .{ .xchg, .rm, &.{ .r8, .rm8 }, &.{ 0x86 }, 0, .rex, .none },
809 .{ .xchg, .mr, &.{ .rm16, .r16 }, &.{ 0x87 }, 0, .short, .none },
810 .{ .xchg, .rm, &.{ .r16, .rm16 }, &.{ 0x87 }, 0, .short, .none },
811 .{ .xchg, .mr, &.{ .rm32, .r32 }, &.{ 0x87 }, 0, .none, .none },
812 .{ .xchg, .mr, &.{ .rm64, .r64 }, &.{ 0x87 }, 0, .long, .none },
813 .{ .xchg, .rm, &.{ .r32, .rm32 }, &.{ 0x87 }, 0, .none, .none },
814 .{ .xchg, .rm, &.{ .r64, .rm64 }, &.{ 0x87 }, 0, .long, .none },
815
816 .{ .xor, .zi, &.{ .al, .imm8 }, &.{ 0x34 }, 0, .none, .none },
817 .{ .xor, .zi, &.{ .ax, .imm16 }, &.{ 0x35 }, 0, .short, .none },
818 .{ .xor, .zi, &.{ .eax, .imm32 }, &.{ 0x35 }, 0, .none, .none },
819 .{ .xor, .zi, &.{ .rax, .imm32s }, &.{ 0x35 }, 0, .long, .none },
820 .{ .xor, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 6, .none, .none },
821 .{ .xor, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 6, .rex, .none },
822 .{ .xor, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 6, .short, .none },
823 .{ .xor, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 6, .none, .none },
824 .{ .xor, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 6, .long, .none },
825 .{ .xor, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 6, .short, .none },
826 .{ .xor, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 6, .none, .none },
827 .{ .xor, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 6, .long, .none },
828 .{ .xor, .mr, &.{ .rm8, .r8 }, &.{ 0x30 }, 0, .none, .none },
829 .{ .xor, .mr, &.{ .rm8, .r8 }, &.{ 0x30 }, 0, .rex, .none },
830 .{ .xor, .mr, &.{ .rm16, .r16 }, &.{ 0x31 }, 0, .short, .none },
831 .{ .xor, .mr, &.{ .rm32, .r32 }, &.{ 0x31 }, 0, .none, .none },
832 .{ .xor, .mr, &.{ .rm64, .r64 }, &.{ 0x31 }, 0, .long, .none },
833 .{ .xor, .rm, &.{ .r8, .rm8 }, &.{ 0x32 }, 0, .none, .none },
834 .{ .xor, .rm, &.{ .r8, .rm8 }, &.{ 0x32 }, 0, .rex, .none },
835 .{ .xor, .rm, &.{ .r16, .rm16 }, &.{ 0x33 }, 0, .short, .none },
836 .{ .xor, .rm, &.{ .r32, .rm32 }, &.{ 0x33 }, 0, .none, .none },
837 .{ .xor, .rm, &.{ .r64, .rm64 }, &.{ 0x33 }, 0, .long, .none },
831838
832839 // SSE
833 .{ .addss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x58 }, 0, .sse },
840 .{ .addps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x58 }, 0, .none, .sse },
834841
835 .{ .andnps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x55 }, 0, .sse },
842 .{ .addss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x58 }, 0, .none, .sse },
836843
837 .{ .andps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x54 }, 0, .sse },
844 .{ .andnps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x55 }, 0, .none, .sse },
838845
839 .{ .cmpss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0xf3, 0x0f, 0xc2 }, 0, .sse },
846 .{ .andps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x54 }, 0, .none, .sse },
840847
841 .{ .cvtsi2ss, .rm, &.{ .xmm, .rm32 }, &.{ 0xf3, 0x0f, 0x2a }, 0, .sse },
842 .{ .cvtsi2ss, .rm, &.{ .xmm, .rm64 }, &.{ 0xf3, 0x0f, 0x2a }, 0, .sse_long },
848 .{ .cmpss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0xf3, 0x0f, 0xc2 }, 0, .none, .sse },
843849
844 .{ .divss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5e }, 0, .sse },
850 .{ .cvtsi2ss, .rm, &.{ .xmm, .rm32 }, &.{ 0xf3, 0x0f, 0x2a }, 0, .none, .sse },
851 .{ .cvtsi2ss, .rm, &.{ .xmm, .rm64 }, &.{ 0xf3, 0x0f, 0x2a }, 0, .long, .sse },
845852
846 .{ .maxss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5f }, 0, .sse },
853 .{ .divps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x5e }, 0, .none, .sse },
847854
848 .{ .minss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5d }, 0, .sse },
855 .{ .divss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5e }, 0, .none, .sse },
849856
850 .{ .movaps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x28 }, 0, .sse },
851 .{ .movaps, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x0f, 0x29 }, 0, .sse },
857 .{ .maxps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x5f }, 0, .none, .sse },
852858
853 .{ .movss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x10 }, 0, .sse },
854 .{ .movss, .mr, &.{ .xmm_m32, .xmm }, &.{ 0xf3, 0x0f, 0x11 }, 0, .sse },
859 .{ .maxss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5f }, 0, .none, .sse },
855860
856 .{ .movups, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x10 }, 0, .sse },
857 .{ .movups, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x0f, 0x11 }, 0, .sse },
861 .{ .minps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x5d }, 0, .none, .sse },
858862
859 .{ .mulss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x59 }, 0, .sse },
863 .{ .minss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5d }, 0, .none, .sse },
860864
861 .{ .orps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x56 }, 0, .sse },
865 .{ .movaps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x28 }, 0, .none, .sse },
866 .{ .movaps, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x0f, 0x29 }, 0, .none, .sse },
862867
863 .{ .subss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5c }, 0, .sse },
868 .{ .movhlps, .rm, &.{ .xmm, .xmm }, &.{ 0x0f, 0x12 }, 0, .none, .sse },
864869
865 .{ .sqrtps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x51 }, 0, .sse },
866 .{ .sqrtss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x51 }, 0, .sse },
870 .{ .movss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x10 }, 0, .none, .sse },
871 .{ .movss, .mr, &.{ .xmm_m32, .xmm }, &.{ 0xf3, 0x0f, 0x11 }, 0, .none, .sse },
867872
868 .{ .ucomiss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0x0f, 0x2e }, 0, .sse },
873 .{ .movups, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x10 }, 0, .none, .sse },
874 .{ .movups, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x0f, 0x11 }, 0, .none, .sse },
869875
870 .{ .xorps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x57 }, 0, .sse },
876 .{ .mulps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x59 }, 0, .none, .sse },
877
878 .{ .mulss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x59 }, 0, .none, .sse },
879
880 .{ .orps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x56 }, 0, .none, .sse },
881
882 .{ .subps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x5c }, 0, .none, .sse },
883
884 .{ .subss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5c }, 0, .none, .sse },
885
886 .{ .sqrtps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x51 }, 0, .none, .sse },
887
888 .{ .sqrtss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x51 }, 0, .none, .sse },
889
890 .{ .ucomiss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0x0f, 0x2e }, 0, .none, .sse },
891
892 .{ .xorps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x57 }, 0, .none, .sse },
871893
872894 // SSE2
873 .{ .addsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x58 }, 0, .sse2 },
895 .{ .addpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x58 }, 0, .none, .sse2 },
896
897 .{ .addsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x58 }, 0, .none, .sse2 },
898
899 .{ .andnpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x55 }, 0, .none, .sse2 },
900
901 .{ .andpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x54 }, 0, .none, .sse2 },
902
903 .{ .cmpsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0xf2, 0x0f, 0xc2 }, 0, .none, .sse2 },
904
905 .{ .cvtsd2ss, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5a }, 0, .none, .sse2 },
906
907 .{ .cvtsi2sd, .rm, &.{ .xmm, .rm32 }, &.{ 0xf2, 0x0f, 0x2a }, 0, .none, .sse2 },
908 .{ .cvtsi2sd, .rm, &.{ .xmm, .rm64 }, &.{ 0xf2, 0x0f, 0x2a }, 0, .long, .sse2 },
909
910 .{ .cvtss2sd, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5a }, 0, .none, .sse2 },
911
912 .{ .divpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x5e }, 0, .none, .sse2 },
913
914 .{ .divsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5e }, 0, .none, .sse2 },
915
916 .{ .maxpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x5f }, 0, .none, .sse2 },
917
918 .{ .maxsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5f }, 0, .none, .sse2 },
919
920 .{ .minpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x5d }, 0, .none, .sse2 },
921
922 .{ .minsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5d }, 0, .none, .sse2 },
923
924 .{ .movapd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x28 }, 0, .none, .sse2 },
925 .{ .movapd, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x66, 0x0f, 0x29 }, 0, .none, .sse2 },
926
927 .{ .movd, .rm, &.{ .xmm, .rm32 }, &.{ 0x66, 0x0f, 0x6e }, 0, .none, .sse2 },
928 .{ .movd, .mr, &.{ .rm32, .xmm }, &.{ 0x66, 0x0f, 0x7e }, 0, .none, .sse2 },
874929
875 .{ .andnpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x55 }, 0, .sse2 },
930 .{ .movq, .rm, &.{ .xmm, .rm64 }, &.{ 0x66, 0x0f, 0x6e }, 0, .long, .sse2 },
931 .{ .movq, .mr, &.{ .rm64, .xmm }, &.{ 0x66, 0x0f, 0x7e }, 0, .long, .sse2 },
876932
877 .{ .andpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x54 }, 0, .sse2 },
933 .{ .movq, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf3, 0x0f, 0x7e }, 0, .none, .sse2 },
934 .{ .movq, .mr, &.{ .xmm_m64, .xmm }, &.{ 0x66, 0x0f, 0xd6 }, 0, .none, .sse2 },
878935
879 .{ .cmpsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0xf2, 0x0f, 0xc2 }, 0, .sse2 },
936 .{ .movupd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x10 }, 0, .none, .sse2 },
937 .{ .movupd, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x66, 0x0f, 0x11 }, 0, .none, .sse2 },
880938
881 .{ .cvtsd2ss, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5a }, 0, .sse2 },
939 .{ .mulpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x59 }, 0, .none, .sse2 },
882940
883 .{ .cvtsi2sd, .rm, &.{ .xmm, .rm32 }, &.{ 0xf2, 0x0f, 0x2a }, 0, .sse2 },
884 .{ .cvtsi2sd, .rm, &.{ .xmm, .rm64 }, &.{ 0xf2, 0x0f, 0x2a }, 0, .sse2_long },
941 .{ .mulsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x59 }, 0, .none, .sse2 },
885942
886 .{ .cvtss2sd, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5a }, 0, .sse2 },
943 .{ .orpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x56 }, 0, .none, .sse2 },
887944
888 .{ .divsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5e }, 0, .sse2 },
945 .{ .pextrw, .rmi, &.{ .r32, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0xc5 }, 0, .none, .sse2 },
889946
890 .{ .maxsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5f }, 0, .sse2 },
947 .{ .pinsrw, .rmi, &.{ .xmm, .r32_m16, .imm8 }, &.{ 0x66, 0x0f, 0xc4 }, 0, .none, .sse2 },
891948
892 .{ .minsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5d }, 0, .sse2 },
949 .{ .pshufhw, .rmi, &.{ .xmm, .xmm_m128, .imm8 }, &.{ 0xf3, 0x0f, 0x70 }, 0, .none, .sse2 },
893950
894 .{ .movapd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x28 }, 0, .sse2 },
895 .{ .movapd, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x66, 0x0f, 0x29 }, 0, .sse2 },
951 .{ .pshuflw, .rmi, &.{ .xmm, .xmm_m128, .imm8 }, &.{ 0xf2, 0x0f, 0x70 }, 0, .none, .sse2 },
896952
897 .{ .movd, .rm, &.{ .xmm, .rm32 }, &.{ 0x66, 0x0f, 0x6e }, 0, .sse2 },
898 .{ .movd, .mr, &.{ .rm32, .xmm }, &.{ 0x66, 0x0f, 0x7e }, 0, .sse2 },
953 .{ .psrlw, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xd1 }, 0, .none, .sse2 },
954 .{ .psrlw, .mi, &.{ .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x71 }, 2, .none, .sse2 },
955 .{ .psrld, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xd2 }, 0, .none, .sse2 },
956 .{ .psrld, .mi, &.{ .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x72 }, 2, .none, .sse2 },
957 .{ .psrlq, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xd3 }, 0, .none, .sse2 },
958 .{ .psrlq, .mi, &.{ .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x73 }, 2, .none, .sse2 },
899959
900 .{ .movq, .rm, &.{ .xmm, .rm64 }, &.{ 0x66, 0x0f, 0x6e }, 0, .sse2_long },
901 .{ .movq, .mr, &.{ .rm64, .xmm }, &.{ 0x66, 0x0f, 0x7e }, 0, .sse2_long },
960 .{ .punpckhbw, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x68 }, 0, .none, .sse2 },
961 .{ .punpckhwd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x69 }, 0, .none, .sse2 },
962 .{ .punpckhdq, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x6a }, 0, .none, .sse2 },
963 .{ .punpckhqdq, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x6d }, 0, .none, .sse2 },
902964
903 .{ .movq, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf3, 0x0f, 0x7e }, 0, .sse2 },
904 .{ .movq, .mr, &.{ .xmm_m64, .xmm }, &.{ 0x66, 0x0f, 0xd6 }, 0, .sse2 },
965 .{ .punpcklbw, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x60 }, 0, .none, .sse2 },
966 .{ .punpcklwd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x61 }, 0, .none, .sse2 },
967 .{ .punpckldq, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x62 }, 0, .none, .sse2 },
968 .{ .punpcklqdq, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x6c }, 0, .none, .sse2 },
905969
906 .{ .movupd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x10 }, 0, .sse2 },
907 .{ .movupd, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x66, 0x0f, 0x11 }, 0, .sse2 },
970 .{ .sqrtpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x51 }, 0, .none, .sse2 },
908971
909 .{ .mulsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x59 }, 0, .sse2 },
972 .{ .sqrtsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x51 }, 0, .none, .sse2 },
910973
911 .{ .orpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x56 }, 0, .sse2 },
974 .{ .subpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x5c }, 0, .none, .sse2 },
912975
913 .{ .pextrw, .mri, &.{ .r16, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0xc5 }, 0, .sse2 },
976 .{ .subsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5c }, 0, .none, .sse2 },
914977
915 .{ .pinsrw, .rmi, &.{ .xmm, .rm16, .imm8 }, &.{ 0x66, 0x0f, 0xc4 }, 0, .sse2 },
978 .{ .movsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x10 }, 0, .none, .sse2 },
979 .{ .movsd, .mr, &.{ .xmm_m64, .xmm }, &.{ 0xf2, 0x0f, 0x11 }, 0, .none, .sse2 },
916980
917 .{ .sqrtpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x51 }, 0, .sse2 },
918 .{ .sqrtsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x51 }, 0, .sse2 },
981 .{ .ucomisd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x2e }, 0, .none, .sse2 },
919982
920 .{ .subsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5c }, 0, .sse2 },
983 .{ .xorpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x57 }, 0, .none, .sse2 },
921984
922 .{ .movsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x10 }, 0, .sse2 },
923 .{ .movsd, .mr, &.{ .xmm_m64, .xmm }, &.{ 0xf2, 0x0f, 0x11 }, 0, .sse2 },
985 // SSE3
986 .{ .movddup, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x12 }, 0, .none, .sse3 },
924987
925 .{ .ucomisd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x2e }, 0, .sse2 },
988 .{ .movshdup, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0x16 }, 0, .none, .sse3 },
926989
927 .{ .xorpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x57 }, 0, .sse2 },
990 .{ .movsldup, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0x12 }, 0, .none, .sse3 },
928991
929992 // SSE4.1
930 .{ .pextrw, .mri, &.{ .rm16, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x15 }, 0, .sse4_1 },
993 .{ .pextrb, .mri, &.{ .r32_m8, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x14 }, 0, .none, .sse4_1 },
994 .{ .pextrd, .mri, &.{ .rm32, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x16 }, 0, .none, .sse4_1 },
995 .{ .pextrq, .mri, &.{ .rm64, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x16 }, 0, .long, .sse4_1 },
996
997 .{ .pextrw, .mri, &.{ .r32_m16, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x15 }, 0, .none, .sse4_1 },
998
999 .{ .pinsrb, .rmi, &.{ .xmm, .r32_m8, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x20 }, 0, .none, .sse4_1 },
1000 .{ .pinsrd, .rmi, &.{ .xmm, .rm32, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x22 }, 0, .none, .sse4_1 },
1001 .{ .pinsrq, .rmi, &.{ .xmm, .rm64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x22 }, 0, .long, .sse4_1 },
1002
1003 .{ .roundpd, .rmi, &.{ .xmm, .xmm_m128, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x09 }, 0, .none, .sse4_1 },
1004
1005 .{ .roundps, .rmi, &.{ .xmm, .xmm_m128, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x08 }, 0, .none, .sse4_1 },
1006
1007 .{ .roundsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .none, .sse4_1 },
1008
1009 .{ .roundss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0a }, 0, .none, .sse4_1 },
1010
1011 // AVX
1012 .{ .vaddpd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x58 }, 0, .vex_128_wig, .avx },
1013 .{ .vaddpd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x58 }, 0, .vex_256_wig, .avx },
1014
1015 .{ .vaddps, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x0f, 0x58 }, 0, .vex_128_wig, .avx },
1016 .{ .vaddps, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x0f, 0x58 }, 0, .vex_256_wig, .avx },
1017
1018 .{ .vaddsd, .rvm, &.{ .xmm, .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x58 }, 0, .vex_lig_wig, .avx },
1019
1020 .{ .vaddss, .rvm, &.{ .xmm, .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x58 }, 0, .vex_lig_wig, .avx },
1021
1022 .{ .vcvtsd2ss, .rvm, &.{ .xmm, .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5a }, 0, .vex_lig_wig, .avx },
1023
1024 .{ .vcvtsi2sd, .rvm, &.{ .xmm, .xmm, .rm32 }, &.{ 0xf2, 0x0f, 0x2a }, 0, .vex_lig_w0, .avx },
1025 .{ .vcvtsi2sd, .rvm, &.{ .xmm, .xmm, .rm64 }, &.{ 0xf2, 0x0f, 0x2a }, 0, .vex_lig_w1, .avx },
1026
1027 .{ .vcvtsi2ss, .rvm, &.{ .xmm, .xmm, .rm32 }, &.{ 0xf2, 0x0f, 0x2a }, 0, .vex_lig_w0, .avx },
1028 .{ .vcvtsi2ss, .rvm, &.{ .xmm, .xmm, .rm64 }, &.{ 0xf2, 0x0f, 0x2a }, 0, .vex_lig_w1, .avx },
1029
1030 .{ .vcvtss2sd, .rvm, &.{ .xmm, .xmm, .xmm_m32 }, &.{ 0xf2, 0x0f, 0x5a }, 0, .vex_lig_wig, .avx },
1031
1032 .{ .vdivpd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x5e }, 0, .vex_128_wig, .avx },
1033 .{ .vdivpd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x5e }, 0, .vex_256_wig, .avx },
1034
1035 .{ .vdivps, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x0f, 0x5e }, 0, .vex_128_wig, .avx },
1036 .{ .vdivps, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x0f, 0x5e }, 0, .vex_256_wig, .avx },
1037
1038 .{ .vdivsd, .rvm, &.{ .xmm, .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5e }, 0, .vex_lig_wig, .avx },
1039
1040 .{ .vdivss, .rvm, &.{ .xmm, .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5e }, 0, .vex_lig_wig, .avx },
1041
1042 .{ .vmaxpd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x5f }, 0, .vex_128_wig, .avx },
1043 .{ .vmaxpd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x5f }, 0, .vex_256_wig, .avx },
1044
1045 .{ .vmaxps, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x0f, 0x5f }, 0, .vex_128_wig, .avx },
1046 .{ .vmaxps, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x0f, 0x5f }, 0, .vex_256_wig, .avx },
1047
1048 .{ .vmaxsd, .rvm, &.{ .xmm, .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5f }, 0, .vex_lig_wig, .avx },
1049
1050 .{ .vmaxss, .rvm, &.{ .xmm, .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5f }, 0, .vex_lig_wig, .avx },
1051
1052 .{ .vminpd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x5d }, 0, .vex_128_wig, .avx },
1053 .{ .vminpd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x5d }, 0, .vex_256_wig, .avx },
1054
1055 .{ .vminps, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x0f, 0x5d }, 0, .vex_128_wig, .avx },
1056 .{ .vminps, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x0f, 0x5d }, 0, .vex_256_wig, .avx },
1057
1058 .{ .vminsd, .rvm, &.{ .xmm, .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5d }, 0, .vex_lig_wig, .avx },
1059
1060 .{ .vminss, .rvm, &.{ .xmm, .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5d }, 0, .vex_lig_wig, .avx },
1061
1062 .{ .vmovapd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x28 }, 0, .vex_128_wig, .avx },
1063 .{ .vmovapd, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x66, 0x0f, 0x29 }, 0, .vex_128_wig, .avx },
1064 .{ .vmovapd, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x28 }, 0, .vex_256_wig, .avx },
1065 .{ .vmovapd, .mr, &.{ .ymm_m256, .ymm }, &.{ 0x66, 0x0f, 0x29 }, 0, .vex_256_wig, .avx },
1066
1067 .{ .vmovaps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x28 }, 0, .vex_128_wig, .avx },
1068 .{ .vmovaps, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x0f, 0x29 }, 0, .vex_128_wig, .avx },
1069 .{ .vmovaps, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x0f, 0x28 }, 0, .vex_256_wig, .avx },
1070 .{ .vmovaps, .mr, &.{ .ymm_m256, .ymm }, &.{ 0x0f, 0x29 }, 0, .vex_256_wig, .avx },
1071
1072 .{ .vmovddup, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x12 }, 0, .vex_128_wig, .avx },
1073 .{ .vmovddup, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0xf2, 0x0f, 0x12 }, 0, .vex_256_wig, .avx },
1074
1075 .{ .vmovhlps, .rvm, &.{ .xmm, .xmm, .xmm }, &.{ 0x0f, 0x12 }, 0, .vex_128_wig, .avx },
1076
1077 .{ .vmovsd, .rvm, &.{ .xmm, .xmm, .xmm }, &.{ 0xf2, 0x0f, 0x10 }, 0, .vex_lig_wig, .avx },
1078 .{ .vmovsd, .rm, &.{ .xmm, .m64 }, &.{ 0xf2, 0x0f, 0x10 }, 0, .vex_lig_wig, .avx },
1079 .{ .vmovsd, .mvr, &.{ .xmm, .xmm, .xmm }, &.{ 0xf2, 0x0f, 0x11 }, 0, .vex_lig_wig, .avx },
1080 .{ .vmovsd, .mr, &.{ .m64, .xmm }, &.{ 0xf2, 0x0f, 0x11 }, 0, .vex_lig_wig, .avx },
1081
1082 .{ .vmovshdup, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0x16 }, 0, .vex_128_wig, .avx },
1083 .{ .vmovshdup, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0xf3, 0x0f, 0x16 }, 0, .vex_256_wig, .avx },
1084
1085 .{ .vmovsldup, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0x12 }, 0, .vex_128_wig, .avx },
1086 .{ .vmovsldup, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0xf3, 0x0f, 0x12 }, 0, .vex_256_wig, .avx },
1087
1088 .{ .vmovss, .rvm, &.{ .xmm, .xmm, .xmm }, &.{ 0xf3, 0x0f, 0x10 }, 0, .vex_lig_wig, .avx },
1089 .{ .vmovss, .rm, &.{ .xmm, .m32 }, &.{ 0xf3, 0x0f, 0x10 }, 0, .vex_lig_wig, .avx },
1090 .{ .vmovss, .mvr, &.{ .xmm, .xmm, .xmm }, &.{ 0xf3, 0x0f, 0x11 }, 0, .vex_lig_wig, .avx },
1091 .{ .vmovss, .mr, &.{ .m32, .xmm }, &.{ 0xf3, 0x0f, 0x11 }, 0, .vex_lig_wig, .avx },
1092
1093 .{ .vmovupd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x10 }, 0, .vex_128_wig, .avx },
1094 .{ .vmovupd, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x66, 0x0f, 0x11 }, 0, .vex_128_wig, .avx },
1095 .{ .vmovupd, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x10 }, 0, .vex_256_wig, .avx },
1096 .{ .vmovupd, .mr, &.{ .ymm_m256, .ymm }, &.{ 0x66, 0x0f, 0x11 }, 0, .vex_256_wig, .avx },
1097
1098 .{ .vmovups, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x10 }, 0, .vex_128_wig, .avx },
1099 .{ .vmovups, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x0f, 0x11 }, 0, .vex_128_wig, .avx },
1100 .{ .vmovups, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x0f, 0x10 }, 0, .vex_256_wig, .avx },
1101 .{ .vmovups, .mr, &.{ .ymm_m256, .ymm }, &.{ 0x0f, 0x11 }, 0, .vex_256_wig, .avx },
1102
1103 .{ .vmulpd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x59 }, 0, .vex_128_wig, .avx },
1104 .{ .vmulpd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x59 }, 0, .vex_256_wig, .avx },
1105
1106 .{ .vmulps, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x0f, 0x59 }, 0, .vex_128_wig, .avx },
1107 .{ .vmulps, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x0f, 0x59 }, 0, .vex_256_wig, .avx },
1108
1109 .{ .vmulsd, .rvm, &.{ .xmm, .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x59 }, 0, .vex_lig_wig, .avx },
1110
1111 .{ .vmulss, .rvm, &.{ .xmm, .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x59 }, 0, .vex_lig_wig, .avx },
1112
1113 .{ .vpextrb, .mri, &.{ .r32_m8, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x14 }, 0, .vex_128_w0, .avx },
1114 .{ .vpextrd, .mri, &.{ .rm32, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x16 }, 0, .vex_128_w0, .avx },
1115 .{ .vpextrq, .mri, &.{ .rm64, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x16 }, 0, .vex_128_w1, .avx },
1116
1117 .{ .vpextrw, .rmi, &.{ .r32, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x15 }, 0, .vex_128_wig, .avx },
1118 .{ .vpextrw, .mri, &.{ .r32_m16, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x15 }, 0, .vex_128_wig, .avx },
1119
1120 .{ .vpinsrb, .rmi, &.{ .xmm, .r32_m8, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x20 }, 0, .vex_128_w0, .avx },
1121 .{ .vpinsrd, .rmi, &.{ .xmm, .rm32, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x22 }, 0, .vex_128_w0, .avx },
1122 .{ .vpinsrq, .rmi, &.{ .xmm, .rm64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x22 }, 0, .vex_128_w1, .avx },
1123
1124 .{ .vpinsrw, .rvmi, &.{ .xmm, .xmm, .r32_m16, .imm8 }, &.{ 0x66, 0x0f, 0xc4 }, 0, .vex_128_wig, .avx },
1125
1126 .{ .vpsrlw, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xd1 }, 0, .vex_128_wig, .avx },
1127 .{ .vpsrlw, .vmi, &.{ .xmm, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x71 }, 2, .vex_128_wig, .avx },
1128 .{ .vpsrld, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xd2 }, 0, .vex_128_wig, .avx },
1129 .{ .vpsrld, .vmi, &.{ .xmm, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x72 }, 2, .vex_128_wig, .avx },
1130 .{ .vpsrlq, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xd3 }, 0, .vex_128_wig, .avx },
1131 .{ .vpsrlq, .vmi, &.{ .xmm, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x73 }, 2, .vex_128_wig, .avx },
1132
1133 .{ .vpunpckhbw, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x68 }, 0, .vex_128_wig, .avx },
1134 .{ .vpunpckhwd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x69 }, 0, .vex_128_wig, .avx },
1135 .{ .vpunpckhdq, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x6a }, 0, .vex_128_wig, .avx },
1136 .{ .vpunpckhqdq, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x6d }, 0, .vex_128_wig, .avx },
1137
1138 .{ .vpunpcklbw, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x60 }, 0, .vex_128_wig, .avx },
1139 .{ .vpunpcklwd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x61 }, 0, .vex_128_wig, .avx },
1140 .{ .vpunpckldq, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x62 }, 0, .vex_128_wig, .avx },
1141 .{ .vpunpcklqdq, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x6c }, 0, .vex_128_wig, .avx },
1142
1143 .{ .vroundpd, .rmi, &.{ .xmm, .xmm_m128, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x09 }, 0, .vex_128_wig, .avx },
1144 .{ .vroundpd, .rmi, &.{ .ymm, .ymm_m256, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x09 }, 0, .vex_256_wig, .avx },
1145
1146 .{ .vroundps, .rmi, &.{ .xmm, .xmm_m128, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x08 }, 0, .vex_128_wig, .avx },
1147 .{ .vroundps, .rmi, &.{ .ymm, .ymm_m256, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x08 }, 0, .vex_256_wig, .avx },
1148
1149 .{ .vroundsd, .rvmi, &.{ .xmm, .xmm, .xmm_m64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .vex_lig_wig, .avx },
1150
1151 .{ .vroundss, .rvmi, &.{ .xmm, .xmm, .xmm_m32, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0a }, 0, .vex_lig_wig, .avx },
1152
1153 .{ .vsqrtpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x51 }, 0, .vex_128_wig, .avx },
1154 .{ .vsqrtpd, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x51 }, 0, .vex_256_wig, .avx },
1155
1156 .{ .vsqrtps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x51 }, 0, .vex_128_wig, .avx },
1157 .{ .vsqrtps, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x0f, 0x51 }, 0, .vex_256_wig, .avx },
1158
1159 .{ .vsqrtsd, .rvm, &.{ .xmm, .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x51 }, 0, .vex_lig_wig, .avx },
1160
1161 .{ .vsqrtss, .rvm, &.{ .xmm, .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x51 }, 0, .vex_lig_wig, .avx },
1162
1163 .{ .vsubpd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x5c }, 0, .vex_128_wig, .avx },
1164 .{ .vsubpd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x5c }, 0, .vex_256_wig, .avx },
1165
1166 .{ .vsubps, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x0f, 0x5c }, 0, .vex_128_wig, .avx },
1167 .{ .vsubps, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x0f, 0x5c }, 0, .vex_256_wig, .avx },
1168
1169 .{ .vsubsd, .rvm, &.{ .xmm, .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5c }, 0, .vex_lig_wig, .avx },
1170
1171 .{ .vsubss, .rvm, &.{ .xmm, .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5c }, 0, .vex_lig_wig, .avx },
1172
1173 // F16C
1174 .{ .vcvtph2ps, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x38, 0x13 }, 0, .vex_128_w0, .f16c },
1175 .{ .vcvtph2ps, .rm, &.{ .ymm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x13 }, 0, .vex_256_w0, .f16c },
1176
1177 .{ .vcvtps2ph, .mri, &.{ .xmm_m64, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x1d }, 0, .vex_128_w0, .f16c },
1178 .{ .vcvtps2ph, .mri, &.{ .xmm_m128, .ymm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x1d }, 0, .vex_256_w0, .f16c },
1179
1180 // FMA
1181 .{ .vfmadd132pd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x98 }, 0, .vex_128_w1, .fma },
1182 .{ .vfmadd213pd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0xa8 }, 0, .vex_128_w1, .fma },
1183 .{ .vfmadd231pd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0xb8 }, 0, .vex_128_w1, .fma },
1184 .{ .vfmadd132pd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0x98 }, 0, .vex_256_w1, .fma },
1185 .{ .vfmadd213pd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0xa8 }, 0, .vex_256_w1, .fma },
1186 .{ .vfmadd231pd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0xb8 }, 0, .vex_256_w1, .fma },
1187
1188 .{ .vfmadd132ps, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x98 }, 0, .vex_128_w0, .fma },
1189 .{ .vfmadd213ps, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0xa8 }, 0, .vex_128_w0, .fma },
1190 .{ .vfmadd231ps, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0xb8 }, 0, .vex_128_w0, .fma },
1191 .{ .vfmadd132ps, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0x98 }, 0, .vex_256_w0, .fma },
1192 .{ .vfmadd213ps, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0xa8 }, 0, .vex_256_w0, .fma },
1193 .{ .vfmadd231ps, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0xb8 }, 0, .vex_256_w0, .fma },
1194
1195 .{ .vfmadd132sd, .rvm, &.{ .xmm, .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x38, 0x99 }, 0, .vex_lig_w1, .fma },
1196 .{ .vfmadd213sd, .rvm, &.{ .xmm, .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x38, 0xa9 }, 0, .vex_lig_w1, .fma },
1197 .{ .vfmadd231sd, .rvm, &.{ .xmm, .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x38, 0xb9 }, 0, .vex_lig_w1, .fma },
1198
1199 .{ .vfmadd132ss, .rvm, &.{ .xmm, .xmm, .xmm_m32 }, &.{ 0x66, 0x0f, 0x38, 0x99 }, 0, .vex_lig_w0, .fma },
1200 .{ .vfmadd213ss, .rvm, &.{ .xmm, .xmm, .xmm_m32 }, &.{ 0x66, 0x0f, 0x38, 0xa9 }, 0, .vex_lig_w0, .fma },
1201 .{ .vfmadd231ss, .rvm, &.{ .xmm, .xmm, .xmm_m32 }, &.{ 0x66, 0x0f, 0x38, 0xb9 }, 0, .vex_lig_w0, .fma },
1202
1203 // AVX2
1204 .{ .vpsrlw, .rvm, &.{ .ymm, .ymm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xd1 }, 0, .vex_256_wig, .avx2 },
1205 .{ .vpsrlw, .vmi, &.{ .ymm, .ymm, .imm8 }, &.{ 0x66, 0x0f, 0x71 }, 2, .vex_256_wig, .avx2 },
1206 .{ .vpsrld, .rvm, &.{ .ymm, .ymm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xd2 }, 0, .vex_256_wig, .avx2 },
1207 .{ .vpsrld, .vmi, &.{ .ymm, .ymm, .imm8 }, &.{ 0x66, 0x0f, 0x72 }, 2, .vex_256_wig, .avx2 },
1208 .{ .vpsrlq, .rvm, &.{ .ymm, .ymm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xd3 }, 0, .vex_256_wig, .avx2 },
1209 .{ .vpsrlq, .vmi, &.{ .ymm, .ymm, .imm8 }, &.{ 0x66, 0x0f, 0x73 }, 2, .vex_256_wig, .avx2 },
1210
1211 .{ .vpunpckhbw, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x68 }, 0, .vex_256_wig, .avx2 },
1212 .{ .vpunpckhwd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x69 }, 0, .vex_256_wig, .avx2 },
1213 .{ .vpunpckhdq, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x6a }, 0, .vex_256_wig, .avx2 },
1214 .{ .vpunpckhqdq, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x6d }, 0, .vex_256_wig, .avx2 },
9311215
932 .{ .roundss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0a }, 0, .sse4_1 },
933 .{ .roundsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .sse4_1 },
1216 .{ .vpunpcklbw, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x60 }, 0, .vex_256_wig, .avx2 },
1217 .{ .vpunpcklwd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x61 }, 0, .vex_256_wig, .avx2 },
1218 .{ .vpunpckldq, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x62 }, 0, .vex_256_wig, .avx2 },
1219 .{ .vpunpcklqdq, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x6c }, 0, .vex_256_wig, .avx2 },
9341220};
9351221// zig fmt: on
src/link/Dwarf.zig+29-25
......@@ -526,7 +526,7 @@ pub const DeclState = struct {
526526 .ErrorUnion => {
527527 const error_ty = ty.errorUnionSet();
528528 const payload_ty = ty.errorUnionPayload();
529 const payload_align = payload_ty.abiAlignment(target);
529 const payload_align = if (payload_ty.isNoReturn()) 0 else payload_ty.abiAlignment(target);
530530 const error_align = Type.anyerror.abiAlignment(target);
531531 const abi_size = ty.abiSize(target);
532532 const payload_off = if (error_align >= payload_align) Type.anyerror.abiSize(target) else 0;
......@@ -540,31 +540,35 @@ pub const DeclState = struct {
540540 const name = try ty.nameAllocArena(arena, module);
541541 try dbg_info_buffer.writer().print("{s}\x00", .{name});
542542
543 // DW.AT.member
544 try dbg_info_buffer.ensureUnusedCapacity(7);
545 dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member));
546 // DW.AT.name, DW.FORM.string
547 dbg_info_buffer.appendSliceAssumeCapacity("value");
548 dbg_info_buffer.appendAssumeCapacity(0);
549 // DW.AT.type, DW.FORM.ref4
550 var index = dbg_info_buffer.items.len;
551 try dbg_info_buffer.resize(index + 4);
552 try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(u32, index));
553 // DW.AT.data_member_location, DW.FORM.sdata
554 try leb128.writeULEB128(dbg_info_buffer.writer(), payload_off);
543 if (!payload_ty.isNoReturn()) {
544 // DW.AT.member
545 try dbg_info_buffer.ensureUnusedCapacity(7);
546 dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member));
547 // DW.AT.name, DW.FORM.string
548 dbg_info_buffer.appendSliceAssumeCapacity("value");
549 dbg_info_buffer.appendAssumeCapacity(0);
550 // DW.AT.type, DW.FORM.ref4
551 const index = dbg_info_buffer.items.len;
552 try dbg_info_buffer.resize(index + 4);
553 try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(u32, index));
554 // DW.AT.data_member_location, DW.FORM.sdata
555 try leb128.writeULEB128(dbg_info_buffer.writer(), payload_off);
556 }
555557
556 // DW.AT.member
557 try dbg_info_buffer.ensureUnusedCapacity(5);
558 dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member));
559 // DW.AT.name, DW.FORM.string
560 dbg_info_buffer.appendSliceAssumeCapacity("err");
561 dbg_info_buffer.appendAssumeCapacity(0);
562 // DW.AT.type, DW.FORM.ref4
563 index = dbg_info_buffer.items.len;
564 try dbg_info_buffer.resize(index + 4);
565 try self.addTypeRelocGlobal(atom_index, error_ty, @intCast(u32, index));
566 // DW.AT.data_member_location, DW.FORM.sdata
567 try leb128.writeULEB128(dbg_info_buffer.writer(), error_off);
558 {
559 // DW.AT.member
560 try dbg_info_buffer.ensureUnusedCapacity(5);
561 dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member));
562 // DW.AT.name, DW.FORM.string
563 dbg_info_buffer.appendSliceAssumeCapacity("err");
564 dbg_info_buffer.appendAssumeCapacity(0);
565 // DW.AT.type, DW.FORM.ref4
566 const index = dbg_info_buffer.items.len;
567 try dbg_info_buffer.resize(index + 4);
568 try self.addTypeRelocGlobal(atom_index, error_ty, @intCast(u32, index));
569 // DW.AT.data_member_location, DW.FORM.sdata
570 try leb128.writeULEB128(dbg_info_buffer.writer(), error_off);
571 }
568572
569573 // DW.AT.structure_type delimit children
570574 try dbg_info_buffer.append(0);
test/behavior/bugs/12891.zig-6
......@@ -29,7 +29,6 @@ test "inf >= 1" {
2929test "isNan(nan * 1)" {
3030 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3131 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
32 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
3332
3433 const nan_times_one = comptime std.math.nan(f64) * 1;
3534 try std.testing.expect(std.math.isNan(nan_times_one));
......@@ -37,7 +36,6 @@ test "isNan(nan * 1)" {
3736test "runtime isNan(nan * 1)" {
3837 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3938 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
40 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
4139
4240 const nan_times_one = std.math.nan(f64) * 1;
4341 try std.testing.expect(std.math.isNan(nan_times_one));
......@@ -45,7 +43,6 @@ test "runtime isNan(nan * 1)" {
4543test "isNan(nan * 0)" {
4644 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4745 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
4946
5047 const nan_times_zero = comptime std.math.nan(f64) * 0;
5148 try std.testing.expect(std.math.isNan(nan_times_zero));
......@@ -55,7 +52,6 @@ test "isNan(nan * 0)" {
5552test "isNan(inf * 0)" {
5653 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5754 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
58 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
5955
6056 const inf_times_zero = comptime std.math.inf(f64) * 0;
6157 try std.testing.expect(std.math.isNan(inf_times_zero));
......@@ -65,7 +61,6 @@ test "isNan(inf * 0)" {
6561test "runtime isNan(nan * 0)" {
6662 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6763 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
68 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
6964
7065 const nan_times_zero = std.math.nan(f64) * 0;
7166 try std.testing.expect(std.math.isNan(nan_times_zero));
......@@ -75,7 +70,6 @@ test "runtime isNan(nan * 0)" {
7570test "runtime isNan(inf * 0)" {
7671 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7772 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
78 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
7973
8074 const inf_times_zero = std.math.inf(f64) * 0;
8175 try std.testing.expect(std.math.isNan(inf_times_zero));
test/behavior/bugs/2114.zig+2-1
......@@ -9,7 +9,8 @@ fn ctz(x: anytype) usize {
99
1010test "fixed" {
1111 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_x86_64 and
13 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .bmi)) return error.SkipZigTest; // TODO
1314 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1415 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1516 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/error.zig-3
......@@ -757,7 +757,6 @@ test "error union of noreturn used with if" {
757757 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
758758 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
759759 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
760 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
761760 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
762761
763762 NoReturn.a = 64;
......@@ -772,7 +771,6 @@ test "error union of noreturn used with try" {
772771 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
773772 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
774773 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
775 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
776774 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
777775
778776 NoReturn.a = 64;
......@@ -784,7 +782,6 @@ test "error union of noreturn used with catch" {
784782 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
785783 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
786784 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
787 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
788785 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
789786
790787 NoReturn.a = 64;
test/behavior/field_parent_ptr.zig-1
......@@ -2,7 +2,6 @@ const expect = @import("std").testing.expect;
22const builtin = @import("builtin");
33
44test "@fieldParentPtr non-first field" {
5 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
65 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
76 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
87 try testParentFieldPtr(&foo.c);
test/behavior/floatop.zig+17-14
......@@ -8,6 +8,8 @@ const has_f80_rt = switch (builtin.cpu.arch) {
88 .x86_64, .x86 => true,
99 else => false,
1010};
11const no_x86_64_hardware_f16_support = builtin.zig_backend == .stage2_x86_64 and
12 !std.Target.x86.featureSetHas(builtin.cpu.features, .f16c);
1113
1214const epsilon_16 = 0.001;
1315const epsilon = 0.000001;
......@@ -52,7 +54,7 @@ fn testFloatComparisons() !void {
5254}
5355
5456test "different sized float comparisons" {
55 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
57 if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
5658 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5759 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5860 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -134,7 +136,6 @@ fn testSqrt() !void {
134136
135137test "@sqrt with vectors" {
136138 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
137 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
138139 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
139140 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
140141
......@@ -152,7 +153,7 @@ fn testSqrtWithVectors() !void {
152153}
153154
154155test "more @sqrt f16 tests" {
155 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
156 if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
156157 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
157158 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
158159 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -202,7 +203,7 @@ fn testSqrtLegacy(comptime T: type, x: T) !void {
202203}
203204
204205test "@sin" {
205 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
206 if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
206207 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
207208 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
208209 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -241,7 +242,7 @@ fn testSinWithVectors() !void {
241242}
242243
243244test "@cos" {
244 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
245 if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
245246 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
246247 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
247248 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -280,7 +281,7 @@ fn testCosWithVectors() !void {
280281}
281282
282283test "@exp" {
283 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
284 if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
284285 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
285286 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
286287 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -318,7 +319,7 @@ fn testExpWithVectors() !void {
318319}
319320
320321test "@exp2" {
321 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
322 if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
322323 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
323324 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
324325 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -403,7 +404,7 @@ test "@log with @vectors" {
403404}
404405
405406test "@log2" {
406 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
407 if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
407408 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
408409 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
409410 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -445,7 +446,7 @@ fn testLog2WithVectors() !void {
445446}
446447
447448test "@log10" {
448 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
449 if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
449450 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
450451 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
451452 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -617,7 +618,8 @@ fn testFloor() !void {
617618
618619test "@floor with vectors" {
619620 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
620 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
621 if (builtin.zig_backend == .stage2_x86_64 and
622 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
621623 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
622624 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
623625
......@@ -707,7 +709,8 @@ fn testCeil() !void {
707709
708710test "@ceil with vectors" {
709711 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
710 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
712 if (builtin.zig_backend == .stage2_x86_64 and
713 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
711714 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
712715 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
713716
......@@ -797,7 +800,8 @@ fn testTrunc() !void {
797800
798801test "@trunc with vectors" {
799802 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
800 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
803 if (builtin.zig_backend == .stage2_x86_64 and
804 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
801805 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
802806 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
803807
......@@ -878,7 +882,7 @@ fn testTruncLegacy(comptime T: type, x: T) !void {
878882}
879883
880884test "negation f16" {
881 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
885 if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
882886 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
883887 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
884888 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1037,7 +1041,6 @@ test "comptime_float zero divided by zero produces zero" {
10371041}
10381042
10391043test "nan negation f16" {
1040 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
10411044 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10421045 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10431046 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/math.zig+4-2
......@@ -77,7 +77,8 @@ fn testClz() !void {
7777}
7878
7979test "@clz big ints" {
80 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
80 if (builtin.zig_backend == .stage2_x86_64 and
81 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .lzcnt)) return error.SkipZigTest; // TODO
8182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8283 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8384 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -398,7 +399,8 @@ fn testBinaryNot128(comptime Type: type, x: Type) !void {
398399
399400test "division" {
400401 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
401 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
402 if (builtin.zig_backend == .stage2_x86_64 and
403 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
402404 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
403405 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
404406 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/muladd.zig+8-4
......@@ -1,8 +1,12 @@
1const std = @import("std");
12const builtin = @import("builtin");
2const expect = @import("std").testing.expect;
3const expect = std.testing.expect;
4
5const no_x86_64_hardware_fma_support = builtin.zig_backend == .stage2_x86_64 and
6 !std.Target.x86.featureSetHas(builtin.cpu.features, .fma);
37
48test "@mulAdd" {
5 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
9 if (no_x86_64_hardware_fma_support) return error.SkipZigTest; // TODO
610 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
711 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
812 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -116,7 +120,7 @@ fn vector32() !void {
116120
117121test "vector f32" {
118122 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
119 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
123 if (no_x86_64_hardware_fma_support) return error.SkipZigTest; // TODO
120124 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
121125 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
122126 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -139,7 +143,7 @@ fn vector64() !void {
139143
140144test "vector f64" {
141145 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
142 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
146 if (no_x86_64_hardware_fma_support) return error.SkipZigTest; // TODO
143147 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
144148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
145149 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/vector.zig+2-1
......@@ -168,7 +168,8 @@ test "array to vector" {
168168
169169test "array to vector with element type coercion" {
170170 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
171 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
171 if (builtin.zig_backend == .stage2_x86_64 and
172 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .f16c)) return error.SkipZigTest; // TODO
172173 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
173174 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
174175 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO