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: {...@@ -326,7 +326,7 @@ pub const all_features = blk: {
326 };326 };
327 result[@enumToInt(Feature.avx512ifma)] = .{327 result[@enumToInt(Feature.avx512ifma)] = .{
328 .llvm_name = "avx512ifma",328 .llvm_name = "avx512ifma",
329 .description = "Enable AVX-512 Integer Fused Multiple-Add",329 .description = "Enable AVX-512 Integer Fused Multiply-Add",
330 .dependencies = featureSet(&[_]Feature{330 .dependencies = featureSet(&[_]Feature{
331 .avx512f,331 .avx512f,
332 }),332 }),
...@@ -599,14 +599,14 @@ pub const all_features = blk: {...@@ -599,14 +599,14 @@ pub const all_features = blk: {
599 };599 };
600 result[@enumToInt(Feature.fma)] = .{600 result[@enumToInt(Feature.fma)] = .{
601 .llvm_name = "fma",601 .llvm_name = "fma",
602 .description = "Enable three-operand fused multiple-add",602 .description = "Enable three-operand fused multiply-add",
603 .dependencies = featureSet(&[_]Feature{603 .dependencies = featureSet(&[_]Feature{
604 .avx,604 .avx,
605 }),605 }),
606 };606 };
607 result[@enumToInt(Feature.fma4)] = .{607 result[@enumToInt(Feature.fma4)] = .{
608 .llvm_name = "fma4",608 .llvm_name = "fma4",
609 .description = "Enable four-operand fused multiple-add",609 .description = "Enable four-operand fused multiply-add",
610 .dependencies = featureSet(&[_]Feature{610 .dependencies = featureSet(&[_]Feature{
611 .avx,611 .avx,
612 .sse4a,612 .sse4a,
src/arch/x86_64/CodeGen.zig+2140-944
...@@ -205,16 +205,7 @@ pub const MCValue = union(enum) {...@@ -205,16 +205,7 @@ pub const MCValue = union(enum) {
205205
206 fn isMemory(mcv: MCValue) bool {206 fn isMemory(mcv: MCValue) bool {
207 return switch (mcv) {207 return switch (mcv) {
208 .memory,208 .memory, .indirect, .load_frame => true,
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,
218 else => false,209 else => false,
219 };210 };
220 }211 }
...@@ -937,7 +928,7 @@ fn formatWipMir(...@@ -937,7 +928,7 @@ fn formatWipMir(
937 .target = data.self.target,928 .target = data.self.target,
938 .src_loc = data.self.src_loc,929 .src_loc = data.self.src_loc,
939 };930 };
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) {
941 error.LowerFail => {932 error.LowerFail => {
942 defer {933 defer {
943 lower.err_msg.?.deinit(data.self.gpa);934 lower.err_msg.?.deinit(data.self.gpa);
...@@ -955,7 +946,7 @@ fn formatWipMir(...@@ -955,7 +946,7 @@ fn formatWipMir(
955 return;946 return;
956 },947 },
957 else => |e| return e,948 else => |e| return e,
958 }) |lower_inst| try writer.print(" | {}", .{lower_inst});949 }).insts) |lowered_inst| try writer.print(" | {}", .{lowered_inst});
959}950}
960fn fmtWipMir(self: *Self, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir) {951fn fmtWipMir(self: *Self, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir) {
961 return .{ .data = .{ .self = self, .inst = inst } };952 return .{ .data = .{ .self = self, .inst = inst } };
...@@ -982,14 +973,14 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {...@@ -982,14 +973,14 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
982 try self.mir_instructions.ensureUnusedCapacity(gpa, 1);973 try self.mir_instructions.ensureUnusedCapacity(gpa, 1);
983 const result_index = @intCast(Mir.Inst.Index, self.mir_instructions.len);974 const result_index = @intCast(Mir.Inst.Index, self.mir_instructions.len);
984 self.mir_instructions.appendAssumeCapacity(inst);975 self.mir_instructions.appendAssumeCapacity(inst);
985 switch (inst.tag) {976 if (inst.tag != .pseudo or switch (inst.ops) {
986 else => wip_mir_log.debug("{}", .{self.fmtWipMir(result_index)}),977 else => true,
987 .dbg_line,978 .pseudo_dbg_prologue_end_none,
988 .dbg_prologue_end,979 .pseudo_dbg_line_line_column,
989 .dbg_epilogue_begin,980 .pseudo_dbg_epilogue_begin_none,
990 .dead,981 .pseudo_dead_none,
991 => {},982 => false,
992 }983 }) wip_mir_log.debug("{}", .{self.fmtWipMir(result_index)});
993 return result_index;984 return result_index;
994}985}
995986
...@@ -1012,131 +1003,248 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {...@@ -1012,131 +1003,248 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
1012 return result;1003 return result;
1013}1004}
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 {
1016 _ = try self.addInst(.{1008 _ = try self.addInst(.{
1017 .tag = .setcc,1009 .tag = switch (cc) {
1018 .ops = .r_cc,1010 else => .cmov,
1019 .data = .{ .r_cc = .{ .r = reg, .cc = cc } },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 } },
1020 });1026 });
1021}1027}
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 {
1024 _ = try self.addInst(.{1031 _ = try self.addInst(.{
1025 .tag = .setcc,1032 .tag = switch (cc) {
1026 .ops = switch (m) {1033 else => .cmov,
1027 .sib => .m_sib_cc,1034 .z_and_np => unreachable,
1028 .rip => .m_rip_cc,1035 .nz_or_p => .pseudo,
1029 else => unreachable,
1030 },1036 },
1031 .data = .{ .x_cc = .{ .cc = cc, .payload = switch (m) {1037 .ops = switch (cc) {
1032 .sib => try self.addExtra(Mir.MemorySib.encode(m)),1038 else => switch (m) {
1033 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),1039 .sib => .rm_sib,
1034 else => unreachable,1040 .rip => .rm_rip,
1035 } } },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 } },
1036 });1063 });
1037}1064}
10381065
1039fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bits.Condition) !void {1066fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void {
1040 _ = try self.addInst(.{1067 _ = try self.addInst(.{
1041 .tag = .cmovcc,1068 .tag = switch (cc) {
1042 .ops = .rr_cc,1069 else => .set,
1043 .data = .{ .rr_cc = .{ .r1 = reg1, .r2 = reg2, .cc = cc } },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 },
1044 });1087 });
1045}1088}
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 };
1048 _ = try self.addInst(.{1096 _ = try self.addInst(.{
1049 .tag = .cmovcc,1097 .tag = switch (cc) {
1050 .ops = switch (m) {1098 else => .set,
1051 .sib => .rm_sib_cc,1099 .z_and_np, .nz_or_p => .pseudo,
1052 .rip => .rm_rip_cc,1100 },
1053 else => unreachable,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 } },
1054 },1127 },
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 } } },
1060 });1128 });
1061}1129}
10621130
1063fn asmJmpReloc(self: *Self, target: Mir.Inst.Index) !Mir.Inst.Index {1131fn asmJmpReloc(self: *Self, target: Mir.Inst.Index) !Mir.Inst.Index {
1064 return self.addInst(.{1132 return self.addInst(.{
1065 .tag = .jmp_reloc,1133 .tag = .jmp,
1066 .ops = undefined,1134 .ops = .inst,
1067 .data = .{ .inst = target },1135 .data = .{ .inst = .{
1136 .inst = target,
1137 } },
1068 });1138 });
1069}1139}
10701140
1071fn asmJccReloc(self: *Self, target: Mir.Inst.Index, cc: bits.Condition) !Mir.Inst.Index {1141fn asmJccReloc(self: *Self, target: Mir.Inst.Index, cc: bits.Condition) !Mir.Inst.Index {
1072 return self.addInst(.{1142 return self.addInst(.{
1073 .tag = .jcc,1143 .tag = switch (cc) {
1074 .ops = .inst_cc,1144 else => .j,
1075 .data = .{ .inst_cc = .{ .inst = target, .cc = cc } },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 } },
1076 });1159 });
1077}1160}
10781161
1079fn asmPlaceholder(self: *Self) !Mir.Inst.Index {1162fn asmPlaceholder(self: *Self) !Mir.Inst.Index {
1080 return self.addInst(.{1163 return self.addInst(.{
1081 .tag = .dead,1164 .tag = .pseudo,
1082 .ops = undefined,1165 .ops = .pseudo_dead_none,
1083 .data = undefined,1166 .data = undefined,
1084 });1167 });
1085}1168}
10861169
1087fn asmOpOnly(self: *Self, tag: Mir.Inst.Tag) !void {1170fn asmOpOnly(self: *Self, tag: Mir.Inst.FixedTag) !void {
1088 _ = try self.addInst(.{1171 _ = try self.addInst(.{
1089 .tag = tag,1172 .tag = tag[1],
1090 .ops = .none,1173 .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,
1091 .data = undefined,1184 .data = undefined,
1092 });1185 });
1093}1186}
10941187
1095fn asmRegister(self: *Self, tag: Mir.Inst.Tag, reg: Register) !void {1188fn asmRegister(self: *Self, tag: Mir.Inst.FixedTag, reg: Register) !void {
1096 _ = try self.addInst(.{1189 _ = try self.addInst(.{
1097 .tag = tag,1190 .tag = tag[1],
1098 .ops = .r,1191 .ops = .r,
1099 .data = .{ .r = reg },1192 .data = .{ .r = .{
1193 .fixes = tag[0],
1194 .r1 = reg,
1195 } },
1100 });1196 });
1101}1197}
11021198
1103fn asmImmediate(self: *Self, tag: Mir.Inst.Tag, imm: Immediate) !void {1199fn asmImmediate(self: *Self, tag: Mir.Inst.FixedTag, imm: Immediate) !void {
1104 _ = try self.addInst(.{1200 _ = try self.addInst(.{
1105 .tag = tag,1201 .tag = tag[1],
1106 .ops = switch (imm) {1202 .ops = switch (imm) {
1107 .signed => .i_s,1203 .signed => .i_s,
1108 .unsigned => .i_u,1204 .unsigned => .i_u,
1109 },1205 },
1110 .data = .{ .i = switch (imm) {1206 .data = .{ .i = .{
1111 .signed => |s| @bitCast(u32, s),1207 .fixes = tag[0],
1112 .unsigned => |u| @intCast(u32, u),1208 .i = switch (imm) {
1209 .signed => |s| @bitCast(u32, s),
1210 .unsigned => |u| @intCast(u32, u),
1211 },
1113 } },1212 } },
1114 });1213 });
1115}1214}
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 {
1118 _ = try self.addInst(.{1217 _ = try self.addInst(.{
1119 .tag = tag,1218 .tag = tag[1],
1120 .ops = .rr,1219 .ops = .rr,
1121 .data = .{ .rr = .{ .r1 = reg1, .r2 = reg2 } },1220 .data = .{ .rr = .{
1221 .fixes = tag[0],
1222 .r1 = reg1,
1223 .r2 = reg2,
1224 } },
1122 });1225 });
1123}1226}
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 {
1126 const ops: Mir.Inst.Ops = switch (imm) {1229 const ops: Mir.Inst.Ops = switch (imm) {
1127 .signed => .ri_s,1230 .signed => .ri_s,
1128 .unsigned => |u| if (math.cast(u32, u)) |_| .ri_u else .ri64,1231 .unsigned => |u| if (math.cast(u32, u)) |_| .ri_u else .ri64,
1129 };1232 };
1130 _ = try self.addInst(.{1233 _ = try self.addInst(.{
1131 .tag = tag,1234 .tag = tag[1],
1132 .ops = ops,1235 .ops = ops,
1133 .data = switch (ops) {1236 .data = switch (ops) {
1134 .ri_s, .ri_u => .{ .ri = .{ .r = reg, .i = switch (imm) {1237 .ri_s, .ri_u => .{ .ri = .{
1135 .signed => |s| @bitCast(u32, s),1238 .fixes = tag[0],
1136 .unsigned => |u| @intCast(u32, u),1239 .r1 = reg,
1137 } } },1240 .i = switch (imm) {
1241 .signed => |s| @bitCast(u32, s),
1242 .unsigned => |u| @intCast(u32, u),
1243 },
1244 } },
1138 .ri64 => .{ .rx = .{1245 .ri64 => .{ .rx = .{
1139 .r = reg,1246 .fixes = tag[0],
1247 .r1 = reg,
1140 .payload = try self.addExtra(Mir.Imm64.encode(imm.unsigned)),1248 .payload = try self.addExtra(Mir.Imm64.encode(imm.unsigned)),
1141 } },1249 } },
1142 else => unreachable,1250 else => unreachable,
...@@ -1146,111 +1254,214 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Imme...@@ -1146,111 +1254,214 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Imme
11461254
1147fn asmRegisterRegisterRegister(1255fn asmRegisterRegisterRegister(
1148 self: *Self,1256 self: *Self,
1149 tag: Mir.Inst.Tag,1257 tag: Mir.Inst.FixedTag,
1150 reg1: Register,1258 reg1: Register,
1151 reg2: Register,1259 reg2: Register,
1152 reg3: Register,1260 reg3: Register,
1153) !void {1261) !void {
1154 _ = try self.addInst(.{1262 _ = try self.addInst(.{
1155 .tag = tag,1263 .tag = tag[1],
1156 .ops = .rrr,1264 .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 } },
1158 });1292 });
1159}1293}
11601294
1161fn asmRegisterRegisterImmediate(1295fn asmRegisterRegisterImmediate(
1162 self: *Self,1296 self: *Self,
1163 tag: Mir.Inst.Tag,1297 tag: Mir.Inst.FixedTag,
1164 reg1: Register,1298 reg1: Register,
1165 reg2: Register,1299 reg2: Register,
1166 imm: Immediate,1300 imm: Immediate,
1167) !void {1301) !void {
1168 _ = try self.addInst(.{1302 _ = try self.addInst(.{
1169 .tag = tag,1303 .tag = tag[1],
1170 .ops = switch (imm) {1304 .ops = switch (imm) {
1171 .signed => .rri_s,1305 .signed => .rri_s,
1172 .unsigned => .rri_u,1306 .unsigned => .rri_u,
1173 },1307 },
1174 .data = .{ .rri = .{ .r1 = reg1, .r2 = reg2, .i = switch (imm) {1308 .data = .{ .rri = .{
1175 .signed => |s| @bitCast(u32, s),1309 .fixes = tag[0],
1176 .unsigned => |u| @intCast(u32, u),1310 .r1 = reg1,
1177 } } },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 } },
1178 });1344 });
1179}1345}
11801346
1181fn asmMemory(self: *Self, tag: Mir.Inst.Tag, m: Memory) !void {1347fn asmMemory(self: *Self, tag: Mir.Inst.FixedTag, m: Memory) !void {
1182 _ = try self.addInst(.{1348 _ = try self.addInst(.{
1183 .tag = tag,1349 .tag = tag[1],
1184 .ops = switch (m) {1350 .ops = switch (m) {
1185 .sib => .m_sib,1351 .sib => .m_sib,
1186 .rip => .m_rip,1352 .rip => .m_rip,
1187 else => unreachable,1353 else => unreachable,
1188 },1354 },
1189 .data = .{ .payload = switch (m) {1355 .data = .{ .x = .{
1190 .sib => try self.addExtra(Mir.MemorySib.encode(m)),1356 .fixes = tag[0],
1191 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),1357 .payload = switch (m) {
1192 else => unreachable,1358 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1359 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1360 else => unreachable,
1361 },
1193 } },1362 } },
1194 });1363 });
1195}1364}
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 {
1198 _ = try self.addInst(.{1367 _ = try self.addInst(.{
1199 .tag = tag,1368 .tag = tag[1],
1200 .ops = switch (m) {1369 .ops = switch (m) {
1201 .sib => .rm_sib,1370 .sib => .rm_sib,
1202 .rip => .rm_rip,1371 .rip => .rm_rip,
1203 else => unreachable,1372 else => unreachable,
1204 },1373 },
1205 .data = .{ .rx = .{ .r = reg, .payload = switch (m) {1374 .data = .{ .rx = .{
1206 .sib => try self.addExtra(Mir.MemorySib.encode(m)),1375 .fixes = tag[0],
1207 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),1376 .r1 = reg,
1208 else => unreachable,1377 .payload = switch (m) {
1209 } } },1378 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1379 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1380 else => unreachable,
1381 },
1382 } },
1210 });1383 });
1211}1384}
12121385
1213fn asmRegisterMemoryImmediate(1386fn asmRegisterMemoryImmediate(
1214 self: *Self,1387 self: *Self,
1215 tag: Mir.Inst.Tag,1388 tag: Mir.Inst.FixedTag,
1216 reg: Register,1389 reg: Register,
1217 m: Memory,1390 m: Memory,
1218 imm: Immediate,1391 imm: Immediate,
1219) !void {1392) !void {
1220 _ = try self.addInst(.{1393 _ = try self.addInst(.{
1221 .tag = tag,1394 .tag = tag[1],
1222 .ops = switch (m) {1395 .ops = switch (m) {
1223 .sib => .rmi_sib,1396 .sib => .rmi_sib,
1224 .rip => .rmi_rip,1397 .rip => .rmi_rip,
1225 else => unreachable,1398 else => unreachable,
1226 },1399 },
1227 .data = .{ .rix = .{ .r = reg, .i = @intCast(u8, imm.unsigned), .payload = switch (m) {1400 .data = .{ .rix = .{
1228 .sib => try self.addExtra(Mir.MemorySib.encode(m)),1401 .fixes = tag[0],
1229 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),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,
1230 else => unreachable,1426 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 } },
1232 });1439 });
1233}1440}
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 {
1236 _ = try self.addInst(.{1443 _ = try self.addInst(.{
1237 .tag = tag,1444 .tag = tag[1],
1238 .ops = switch (m) {1445 .ops = switch (m) {
1239 .sib => .mr_sib,1446 .sib => .mr_sib,
1240 .rip => .mr_rip,1447 .rip => .mr_rip,
1241 else => unreachable,1448 else => unreachable,
1242 },1449 },
1243 .data = .{ .rx = .{ .r = reg, .payload = switch (m) {1450 .data = .{ .rx = .{
1244 .sib => try self.addExtra(Mir.MemorySib.encode(m)),1451 .fixes = tag[0],
1245 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),1452 .r1 = reg,
1246 else => unreachable,1453 .payload = switch (m) {
1247 } } },1454 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1455 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1456 else => unreachable,
1457 },
1458 } },
1248 });1459 });
1249}1460}
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 {
1252 _ = try self.addInst(.{1463 _ = try self.addInst(.{
1253 .tag = tag,1464 .tag = tag[1],
1254 .ops = switch (m) {1465 .ops = switch (m) {
1255 .sib => switch (imm) {1466 .sib => switch (imm) {
1256 .signed => .mi_sib_s,1467 .signed => .mi_sib_s,
...@@ -1262,67 +1473,81 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.Tag, m: Memory, imm: Immediate)...@@ -1262,67 +1473,81 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.Tag, m: Memory, imm: Immediate)
1262 },1473 },
1263 else => unreachable,1474 else => unreachable,
1264 },1475 },
1265 .data = .{ .ix = .{ .i = switch (imm) {1476 .data = .{ .x = .{
1266 .signed => |s| @bitCast(u32, s),1477 .fixes = tag[0],
1267 .unsigned => |u| @intCast(u32, u),1478 .payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) {
1268 }, .payload = switch (m) {1479 .signed => |s| @bitCast(u32, s),
1269 .sib => try self.addExtra(Mir.MemorySib.encode(m)),1480 .unsigned => |u| @intCast(u32, u),
1270 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),1481 } }),
1271 else => unreachable,1482 } },
1272 } } },
1273 });1483 });
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 };
1274}1489}
12751490
1276fn asmMemoryRegisterRegister(1491fn asmMemoryRegisterRegister(
1277 self: *Self,1492 self: *Self,
1278 tag: Mir.Inst.Tag,1493 tag: Mir.Inst.FixedTag,
1279 m: Memory,1494 m: Memory,
1280 reg1: Register,1495 reg1: Register,
1281 reg2: Register,1496 reg2: Register,
1282) !void {1497) !void {
1283 _ = try self.addInst(.{1498 _ = try self.addInst(.{
1284 .tag = tag,1499 .tag = tag[1],
1285 .ops = switch (m) {1500 .ops = switch (m) {
1286 .sib => .mrr_sib,1501 .sib => .mrr_sib,
1287 .rip => .mrr_rip,1502 .rip => .mrr_rip,
1288 else => unreachable,1503 else => unreachable,
1289 },1504 },
1290 .data = .{ .rrx = .{ .r1 = reg1, .r2 = reg2, .payload = switch (m) {1505 .data = .{ .rrx = .{
1291 .sib => try self.addExtra(Mir.MemorySib.encode(m)),1506 .fixes = tag[0],
1292 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),1507 .r1 = reg1,
1293 else => unreachable,1508 .r2 = reg2,
1294 } } },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 } },
1295 });1515 });
1296}1516}
12971517
1298fn asmMemoryRegisterImmediate(1518fn asmMemoryRegisterImmediate(
1299 self: *Self,1519 self: *Self,
1300 tag: Mir.Inst.Tag,1520 tag: Mir.Inst.FixedTag,
1301 m: Memory,1521 m: Memory,
1302 reg: Register,1522 reg: Register,
1303 imm: Immediate,1523 imm: Immediate,
1304) !void {1524) !void {
1305 _ = try self.addInst(.{1525 _ = try self.addInst(.{
1306 .tag = tag,1526 .tag = tag[1],
1307 .ops = switch (m) {1527 .ops = switch (m) {
1308 .sib => .mri_sib,1528 .sib => .mri_sib,
1309 .rip => .mri_rip,1529 .rip => .mri_rip,
1310 else => unreachable,1530 else => unreachable,
1311 },1531 },
1312 .data = .{ .rix = .{ .r = reg, .i = @intCast(u8, imm.unsigned), .payload = switch (m) {1532 .data = .{ .rix = .{
1313 .sib => try self.addExtra(Mir.MemorySib.encode(m)),1533 .fixes = tag[0],
1314 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),1534 .r1 = reg,
1315 else => unreachable,1535 .i = @intCast(u8, imm.unsigned),
1316 } } },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 } },
1317 });1542 });
1318}1543}
13191544
1320fn gen(self: *Self) InnerError!void {1545fn gen(self: *Self) InnerError!void {
1321 const cc = self.fn_type.fnCallingConvention();1546 const cc = self.fn_type.fnCallingConvention();
1322 if (cc != .Naked) {1547 if (cc != .Naked) {
1323 try self.asmRegister(.push, .rbp);1548 try self.asmRegister(.{ ._, .push }, .rbp);
1324 const backpatch_push_callee_preserved_regs = try self.asmPlaceholder();1549 const backpatch_push_callee_preserved_regs = try self.asmPlaceholder();
1325 try self.asmRegisterRegister(.mov, .rbp, .rsp);1550 try self.asmRegisterRegister(.{ ._, .mov }, .rbp, .rsp);
1326 const backpatch_frame_align = try self.asmPlaceholder();1551 const backpatch_frame_align = try self.asmPlaceholder();
1327 const backpatch_stack_alloc = try self.asmPlaceholder();1552 const backpatch_stack_alloc = try self.asmPlaceholder();
13281553
...@@ -1346,7 +1571,7 @@ fn gen(self: *Self) InnerError!void {...@@ -1346,7 +1571,7 @@ fn gen(self: *Self) InnerError!void {
1346 else => unreachable,1571 else => unreachable,
1347 }1572 }
13481573
1349 try self.asmOpOnly(.dbg_prologue_end);1574 try self.asmPseudo(.pseudo_dbg_prologue_end_none);
13501575
1351 try self.genBody(self.air.getMainBody());1576 try self.genBody(self.air.getMainBody());
13521577
...@@ -1358,15 +1583,15 @@ fn gen(self: *Self) InnerError!void {...@@ -1358,15 +1583,15 @@ fn gen(self: *Self) InnerError!void {
1358 // }1583 // }
1359 // Eliding the reloc will cause a miscompilation in this case.1584 // Eliding the reloc will cause a miscompilation in this case.
1360 for (self.exitlude_jump_relocs.items) |jmp_reloc| {1585 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 =
1362 @intCast(u32, self.mir_instructions.len);1587 @intCast(u32, self.mir_instructions.len);
1363 }1588 }
13641589
1365 try self.asmOpOnly(.dbg_epilogue_begin);1590 try self.asmPseudo(.pseudo_dbg_epilogue_begin_none);
1366 const backpatch_stack_dealloc = try self.asmPlaceholder();1591 const backpatch_stack_dealloc = try self.asmPlaceholder();
1367 const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder();1592 const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder();
1368 try self.asmRegister(.pop, .rbp);1593 try self.asmRegister(.{ ._, .pop }, .rbp);
1369 try self.asmOpOnly(.ret);1594 try self.asmOpOnly(.{ ._, .ret });
13701595
1371 const frame_layout = try self.computeFrameLayout();1596 const frame_layout = try self.computeFrameLayout();
1372 const need_frame_align = frame_layout.stack_mask != math.maxInt(u32);1597 const need_frame_align = frame_layout.stack_mask != math.maxInt(u32);
...@@ -1376,46 +1601,54 @@ fn gen(self: *Self) InnerError!void {...@@ -1376,46 +1601,54 @@ fn gen(self: *Self) InnerError!void {
1376 self.mir_instructions.set(backpatch_frame_align, .{1601 self.mir_instructions.set(backpatch_frame_align, .{
1377 .tag = .@"and",1602 .tag = .@"and",
1378 .ops = .ri_s,1603 .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 } },
1380 });1608 });
1381 }1609 }
1382 if (need_stack_adjust) {1610 if (need_stack_adjust) {
1383 self.mir_instructions.set(backpatch_stack_alloc, .{1611 self.mir_instructions.set(backpatch_stack_alloc, .{
1384 .tag = .sub,1612 .tag = .sub,
1385 .ops = .ri_s,1613 .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 } },
1387 });1618 });
1388 }1619 }
1389 if (need_frame_align or need_stack_adjust) {1620 if (need_frame_align or need_stack_adjust) {
1390 self.mir_instructions.set(backpatch_stack_dealloc, .{1621 self.mir_instructions.set(backpatch_stack_dealloc, .{
1391 .tag = .mov,1622 .tag = .mov,
1392 .ops = .rr,1623 .ops = .rr,
1393 .data = .{ .rr = .{ .r1 = .rsp, .r2 = .rbp } },1624 .data = .{ .rr = .{
1625 .r1 = .rsp,
1626 .r2 = .rbp,
1627 } },
1394 });1628 });
1395 }1629 }
1396 if (need_save_reg) {1630 if (need_save_reg) {
1397 const save_reg_list = frame_layout.save_reg_list.asInt();
1398 self.mir_instructions.set(backpatch_push_callee_preserved_regs, .{1631 self.mir_instructions.set(backpatch_push_callee_preserved_regs, .{
1399 .tag = .push_regs,1632 .tag = .pseudo,
1400 .ops = undefined,1633 .ops = .pseudo_push_reg_list,
1401 .data = .{ .payload = save_reg_list },1634 .data = .{ .reg_list = frame_layout.save_reg_list },
1402 });1635 });
1403 self.mir_instructions.set(backpatch_pop_callee_preserved_regs, .{1636 self.mir_instructions.set(backpatch_pop_callee_preserved_regs, .{
1404 .tag = .pop_regs,1637 .tag = .pseudo,
1405 .ops = undefined,1638 .ops = .pseudo_pop_reg_list,
1406 .data = .{ .payload = save_reg_list },1639 .data = .{ .reg_list = frame_layout.save_reg_list },
1407 });1640 });
1408 }1641 }
1409 } else {1642 } else {
1410 try self.asmOpOnly(.dbg_prologue_end);1643 try self.asmPseudo(.pseudo_dbg_prologue_end_none);
1411 try self.genBody(self.air.getMainBody());1644 try self.genBody(self.air.getMainBody());
1412 try self.asmOpOnly(.dbg_epilogue_begin);1645 try self.asmPseudo(.pseudo_dbg_epilogue_begin_none);
1413 }1646 }
14141647
1415 // Drop them off at the rbrace.1648 // Drop them off at the rbrace.
1416 _ = try self.addInst(.{1649 _ = try self.addInst(.{
1417 .tag = .dbg_line,1650 .tag = .pseudo,
1418 .ops = undefined,1651 .ops = .pseudo_dbg_line_line_column,
1419 .data = .{ .line_column = .{1652 .data = .{ .line_column = .{
1420 .line = self.end_di_line,1653 .line = self.end_di_line,
1421 .column = self.end_di_column,1654 .column = self.end_di_column,
...@@ -1480,12 +1713,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -1480,12 +1713,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
1480 .log,1713 .log,
1481 .log2,1714 .log2,
1482 .log10,1715 .log10,
1483 .floor,
1484 .ceil,
1485 .round,1716 .round,
1486 .trunc_float,
1487 => try self.airUnaryMath(inst),1717 => 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),
1489 .sqrt => try self.airSqrt(inst),1722 .sqrt => try self.airSqrt(inst),
1490 .neg, .fabs => try self.airFloatSign(inst),1723 .neg, .fabs => try self.airFloatSign(inst),
14911724
...@@ -1731,7 +1964,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {...@@ -1731,7 +1964,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
1731 };1964 };
1732 const tag_val = Value.initPayload(&tag_pl.base);1965 const tag_val = Value.initPayload(&tag_pl.base);
1733 const tag_mcv = try self.genTypedValue(.{ .ty = enum_ty, .val = tag_val });1966 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);
1735 const skip_reloc = try self.asmJccReloc(undefined, .ne);1968 const skip_reloc = try self.asmJccReloc(undefined, .ne);
17361969
1737 try self.genSetMem(1970 try self.genSetMem(
...@@ -1751,7 +1984,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {...@@ -1751,7 +1984,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
1751 try self.airTrap();1984 try self.airTrap();
17521985
1753 for (exitlude_jump_relocs) |reloc| try self.performReloc(reloc);1986 for (exitlude_jump_relocs) |reloc| try self.performReloc(reloc);
1754 try self.asmOpOnly(.ret);1987 try self.asmOpOnly(.{ ._, .ret });
1755 },1988 },
1756 else => return self.fail(1989 else => return self.fail(
1757 "TODO implement {s} for {}",1990 "TODO implement {s} for {}",
...@@ -1919,6 +2152,11 @@ fn computeFrameLayout(self: *Self) !FrameLayout {...@@ -1919,6 +2152,11 @@ fn computeFrameLayout(self: *Self) !FrameLayout {
1919 };2152 };
1920}2153}
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
1922fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex {2160fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex {
1923 const frame_allocs_slice = self.frame_allocs.slice();2161 const frame_allocs_slice = self.frame_allocs.slice();
1924 const frame_size = frame_allocs_slice.items(.abi_size);2162 const frame_size = frame_allocs_slice.items(.abi_size);
...@@ -1962,24 +2200,36 @@ fn allocTempRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool) !MCValue {...@@ -1962,24 +2200,36 @@ fn allocTempRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool) !MCValue {
1962 return self.allocRegOrMemAdvanced(elem_ty, null, reg_ok);2200 return self.allocRegOrMemAdvanced(elem_ty, null, reg_ok);
1963}2201}
19642202
1965fn allocRegOrMemAdvanced(self: *Self, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue {2203fn allocRegOrMemAdvanced(self: *Self, ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue {
1966 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse {2204 const abi_size = math.cast(u32, ty.abiSize(self.target.*)) orelse {
1967 const mod = self.bin_file.options.module.?;2205 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)});
1969 };2207 };
19702208
1971 if (reg_ok) {2209 if (reg_ok) need_mem: {
1972 // Make sure the type can fit in a register before we try to allocate one.2210 if (abi_size <= @as(u32, switch (ty.zigTypeTag()) {
1973 const ptr_bits = self.target.cpu.arch.ptrBitWidth();2211 .Float => switch (ty.floatBits(self.target.*)) {
1974 const ptr_bytes: u64 = @divExact(ptr_bits, 8);2212 16, 32, 64, 128 => 16,
1975 if (abi_size <= ptr_bytes) {2213 80 => break :need_mem,
1976 if (self.register_manager.tryAllocReg(inst, regClassForType(elem_ty))) |reg| {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| {
1977 return MCValue{ .register = registerAlias(reg, abi_size) };2227 return MCValue{ .register = registerAlias(reg, abi_size) };
1978 }2228 }
1979 }2229 }
1980 }2230 }
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.*));
1983 return .{ .load_frame = .{ .index = frame_index } };2233 return .{ .load_frame = .{ .index = frame_index } };
1984}2234}
19852235
...@@ -2172,44 +2422,127 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2172,44 +2422,127 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void {
2172fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {2422fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {
2173 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2423 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2174 const dst_ty = self.air.typeOfIndex(inst);2424 const dst_ty = self.air.typeOfIndex(inst);
2425 const dst_bits = dst_ty.floatBits(self.target.*);
2175 const src_ty = self.air.typeOf(ty_op.operand);2426 const src_ty = self.air.typeOf(ty_op.operand);
2176 if (dst_ty.floatBits(self.target.*) != 32 or src_ty.floatBits(self.target.*) != 64 or2427 const src_bits = src_ty.floatBits(self.target.*);
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 });
21812428
2182 const src_mcv = try self.resolveInst(ty_op.operand);2429 const src_mcv = try self.resolveInst(ty_op.operand);
2183 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))2430 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
2184 src_mcv2431 src_mcv
2185 else2432 else
2186 try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);2433 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);
2188 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);2436 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 });
2191 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });2485 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
2192}2486}
21932487
2194fn airFpext(self: *Self, inst: Air.Inst.Index) !void {2488fn airFpext(self: *Self, inst: Air.Inst.Index) !void {
2195 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2489 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2196 const dst_ty = self.air.typeOfIndex(inst);2490 const dst_ty = self.air.typeOfIndex(inst);
2491 const dst_bits = dst_ty.floatBits(self.target.*);
2197 const src_ty = self.air.typeOf(ty_op.operand);2492 const src_ty = self.air.typeOf(ty_op.operand);
2198 if (dst_ty.floatBits(self.target.*) != 64 or src_ty.floatBits(self.target.*) != 32 or2493 const src_bits = src_ty.floatBits(self.target.*);
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 });
22032494
2204 const src_mcv = try self.resolveInst(ty_op.operand);2495 const src_mcv = try self.resolveInst(ty_op.operand);
2205 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))2496 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
2206 src_mcv2497 src_mcv
2207 else2498 else
2208 try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);2499 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);
2210 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);2502 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 });
2213 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });2546 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
2214}2547}
22152548
...@@ -2241,11 +2574,11 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -2241,11 +2574,11 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
2241 switch (dst_mcv) {2574 switch (dst_mcv) {
2242 .register => |dst_reg| {2575 .register => |dst_reg| {
2243 const min_abi_size = @min(dst_abi_size, src_abi_size);2576 const min_abi_size = @min(dst_abi_size, src_abi_size);
2244 const tag: Mir.Inst.Tag = switch (signedness) {2577 const tag: Mir.Inst.FixedTag = switch (signedness) {
2245 .signed => .movsx,2578 .signed => if (min_abi_size >= 4) .{ ._d, .movsx } else .{ ._, .movsx },
2246 .unsigned => if (min_abi_size > 2) .mov else .movzx,2579 .unsigned => if (min_abi_size >= 4) .{ ._, .mov } else .{ ._, .movzx },
2247 };2580 };
2248 const dst_alias = switch (tag) {2581 const dst_alias = switch (tag[1]) {
2249 .movsx => dst_reg.to64(),2582 .movsx => dst_reg.to64(),
2250 .mov, .movzx => if (min_abi_size > 4) dst_reg.to64() else dst_reg.to32(),2583 .mov, .movzx => if (min_abi_size > 4) dst_reg.to64() else dst_reg.to32(),
2251 else => unreachable,2584 else => unreachable,
...@@ -2274,14 +2607,24 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -2274,14 +2607,24 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
2274 try self.genCopy(min_ty, dst_mcv, src_mcv);2607 try self.genCopy(min_ty, dst_mcv, src_mcv);
2275 const extra = dst_abi_size * 8 - dst_int_info.bits;2608 const extra = dst_abi_size * 8 - dst_int_info.bits;
2276 if (extra > 0) {2609 if (extra > 0) {
2277 try self.genShiftBinOpMir(switch (signedness) {2610 try self.genShiftBinOpMir(
2278 .signed => .sal,2611 switch (signedness) {
2279 .unsigned => .shl,2612 .signed => .{ ._l, .sa },
2280 }, dst_ty, dst_mcv, .{ .immediate = extra });2613 .unsigned => .{ ._l, .sh },
2281 try self.genShiftBinOpMir(switch (signedness) {2614 },
2282 .signed => .sar,2615 dst_ty,
2283 .unsigned => .shr,2616 dst_mcv,
2284 }, dst_ty, dst_mcv, .{ .immediate = extra });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 );
2285 }2628 }
2286 },2629 },
2287 }2630 }
...@@ -2466,8 +2809,8 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -2466,8 +2809,8 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
2466 const reg_bits = self.regBitSize(ty);2809 const reg_bits = self.regBitSize(ty);
2467 const cc: Condition = if (ty.isSignedInt()) cc: {2810 const cc: Condition = if (ty.isSignedInt()) cc: {
2468 try self.genSetReg(limit_reg, ty, dst_mcv);2811 try self.genSetReg(limit_reg, ty, dst_mcv);
2469 try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 });2812 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
2470 try self.genBinOpMir(.xor, ty, limit_mcv, .{2813 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
2471 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,2814 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
2472 });2815 });
2473 break :cc .o;2816 break :cc .o;
...@@ -2477,7 +2820,7 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -2477,7 +2820,7 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
2477 });2820 });
2478 break :cc .c;2821 break :cc .c;
2479 };2822 };
2480 try self.genBinOpMir(.add, ty, dst_mcv, rhs_mcv);2823 try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, rhs_mcv);
24812824
2482 const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2);2825 const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2);
2483 try self.asmCmovccRegisterRegister(2826 try self.asmCmovccRegisterRegister(
...@@ -2517,8 +2860,8 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -2517,8 +2860,8 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
2517 const reg_bits = self.regBitSize(ty);2860 const reg_bits = self.regBitSize(ty);
2518 const cc: Condition = if (ty.isSignedInt()) cc: {2861 const cc: Condition = if (ty.isSignedInt()) cc: {
2519 try self.genSetReg(limit_reg, ty, dst_mcv);2862 try self.genSetReg(limit_reg, ty, dst_mcv);
2520 try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 });2863 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
2521 try self.genBinOpMir(.xor, ty, limit_mcv, .{2864 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
2522 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,2865 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
2523 });2866 });
2524 break :cc .o;2867 break :cc .o;
...@@ -2526,7 +2869,7 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -2526,7 +2869,7 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
2526 try self.genSetReg(limit_reg, ty, .{ .immediate = 0 });2869 try self.genSetReg(limit_reg, ty, .{ .immediate = 0 });
2527 break :cc .c;2870 break :cc .c;
2528 };2871 };
2529 try self.genBinOpMir(.sub, ty, dst_mcv, rhs_mcv);2872 try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, rhs_mcv);
25302873
2531 const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2);2874 const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2);
2532 try self.asmCmovccRegisterRegister(2875 try self.asmCmovccRegisterRegister(
...@@ -2568,9 +2911,9 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -2568,9 +2911,9 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
2568 const reg_bits = self.regBitSize(ty);2911 const reg_bits = self.regBitSize(ty);
2569 const cc: Condition = if (ty.isSignedInt()) cc: {2912 const cc: Condition = if (ty.isSignedInt()) cc: {
2570 try self.genSetReg(limit_reg, ty, lhs_mcv);2913 try self.genSetReg(limit_reg, ty, lhs_mcv);
2571 try self.genBinOpMir(.xor, ty, limit_mcv, rhs_mcv);2914 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, rhs_mcv);
2572 try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 });2915 try self.genShiftBinOpMir(.{ ._, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
2573 try self.genBinOpMir(.xor, ty, limit_mcv, .{2916 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
2574 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,2917 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
2575 });2918 });
2576 break :cc .o;2919 break :cc .o;
...@@ -2683,7 +3026,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2683,7 +3026,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2683 };3026 };
2684 defer if (tmp_lock) |lock| self.register_manager.unlockReg(lock);3027 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);
2687 const cc = Condition.ne;3030 const cc = Condition.ne;
26883031
2689 const tuple_ty = self.air.typeOfIndex(inst);3032 const tuple_ty = self.air.typeOfIndex(inst);
...@@ -2770,12 +3113,17 @@ fn genSetFrameTruncatedOverflowCompare(...@@ -2770,12 +3113,17 @@ fn genSetFrameTruncatedOverflowCompare(
2770 src_mcv;3113 src_mcv;
2771 try self.genSetReg(scratch_reg, hi_limb_ty, hi_limb_mcv);3114 try self.genSetReg(scratch_reg, hi_limb_ty, hi_limb_mcv);
2772 try self.truncateRegister(hi_limb_ty, scratch_reg);3115 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
2775 const eq_reg = temp_regs[2];3118 const eq_reg = temp_regs[2];
2776 if (overflow_cc) |_| {3119 if (overflow_cc) |_| {
2777 try self.asmSetccRegister(eq_reg.to8(), .ne);3120 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 );
2779 }3127 }
27803128
2781 const payload_off = @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*));3129 const payload_off = @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*));
...@@ -2904,28 +3252,25 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2904,28 +3252,25 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2904/// Generates signed or unsigned integer multiplication/division.3252/// Generates signed or unsigned integer multiplication/division.
2905/// Clobbers .rax and .rdx registers.3253/// Clobbers .rax and .rdx registers.
2906/// Quotient is saved in .rax and remainder in .rdx.3254/// Quotient is saved in .rax and remainder in .rdx.
2907fn genIntMulDivOpMir(3255fn genIntMulDivOpMir(self: *Self, tag: Mir.Inst.FixedTag, ty: Type, lhs: MCValue, rhs: MCValue) !void {
2908 self: *Self,
2909 tag: Mir.Inst.Tag,
2910 ty: Type,
2911 lhs: MCValue,
2912 rhs: MCValue,
2913) !void {
2914 const abi_size = @intCast(u32, ty.abiSize(self.target.*));3256 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
2915 if (abi_size > 8) {3257 if (abi_size > 8) {
2916 return self.fail("TODO implement genIntMulDivOpMir for ABI size larger than 8", .{});3258 return self.fail("TODO implement genIntMulDivOpMir for ABI size larger than 8", .{});
2917 }3259 }
29183260
2919 try self.genSetReg(.rax, ty, lhs);3261 try self.genSetReg(.rax, ty, lhs);
2920 switch (tag) {3262 switch (tag[1]) {
2921 else => unreachable,3263 else => unreachable,
2922 .mul, .imul => {},3264 .mul => {},
2923 .div => try self.asmRegisterRegister(.xor, .edx, .edx),3265 .div => switch (tag[0]) {
2924 .idiv => switch (self.regBitSize(ty)) {3266 ._ => try self.asmRegisterRegister(.{ ._, .xor }, .edx, .edx),
2925 8 => try self.asmOpOnly(.cbw),3267 .i_ => switch (self.regBitSize(ty)) {
2926 16 => try self.asmOpOnly(.cwd),3268 8 => try self.asmOpOnly(.{ ._, .cbw }),
2927 32 => try self.asmOpOnly(.cdq),3269 16 => try self.asmOpOnly(.{ ._, .cwd }),
2928 64 => try self.asmOpOnly(.cqo),3270 32 => try self.asmOpOnly(.{ ._, .cdq }),
3271 64 => try self.asmOpOnly(.{ ._, .cqo }),
3272 else => unreachable,
3273 },
2929 else => unreachable,3274 else => unreachable,
2930 },3275 },
2931 }3276 }
...@@ -2963,23 +3308,28 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa...@@ -2963,23 +3308,28 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
2963 const divisor_lock = self.register_manager.lockReg(divisor);3308 const divisor_lock = self.register_manager.lockReg(divisor);
2964 defer if (divisor_lock) |lock| self.register_manager.unlockReg(lock);3309 defer if (divisor_lock) |lock| self.register_manager.unlockReg(lock);
29653310
2966 try self.genIntMulDivOpMir(switch (int_info.signedness) {3311 try self.genIntMulDivOpMir(
2967 .signed => .idiv,3312 switch (int_info.signedness) {
2968 .unsigned => .div,3313 .signed => .{ .i_, .div },
2969 }, ty, .{ .register = dividend }, .{ .register = divisor });3314 .unsigned => .{ ._, .div },
3315 },
3316 ty,
3317 .{ .register = dividend },
3318 .{ .register = divisor },
3319 );
29703320
2971 try self.asmRegisterRegister(3321 try self.asmRegisterRegister(
2972 .xor,3322 .{ ._, .xor },
2973 registerAlias(divisor, abi_size),3323 registerAlias(divisor, abi_size),
2974 registerAlias(dividend, abi_size),3324 registerAlias(dividend, abi_size),
2975 );3325 );
2976 try self.asmRegisterImmediate(3326 try self.asmRegisterImmediate(
2977 .sar,3327 .{ ._r, .sa },
2978 registerAlias(divisor, abi_size),3328 registerAlias(divisor, abi_size),
2979 Immediate.u(int_info.bits - 1),3329 Immediate.u(int_info.bits - 1),
2980 );3330 );
2981 try self.asmRegisterRegister(3331 try self.asmRegisterRegister(
2982 .@"test",3332 .{ ._, .@"test" },
2983 registerAlias(.rdx, abi_size),3333 registerAlias(.rdx, abi_size),
2984 registerAlias(.rdx, abi_size),3334 registerAlias(.rdx, abi_size),
2985 );3335 );
...@@ -2988,7 +3338,7 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa...@@ -2988,7 +3338,7 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
2988 registerAlias(.rdx, abi_size),3338 registerAlias(.rdx, abi_size),
2989 .z,3339 .z,
2990 );3340 );
2991 try self.genBinOpMir(.add, ty, .{ .register = divisor }, .{ .register = .rax });3341 try self.genBinOpMir(.{ ._, .add }, ty, .{ .register = divisor }, .{ .register = .rax });
2992 return MCValue{ .register = divisor };3342 return MCValue{ .register = divisor };
2993}3343}
29943344
...@@ -3110,7 +3460,12 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3110,7 +3460,12 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
3110 const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);3460 const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);
3111 if (err_off > 0) {3461 if (err_off > 0) {
3112 const shift = @intCast(u6, err_off * 8);3462 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 );
3114 } else {3469 } else {
3115 try self.truncateRegister(Type.anyerror, result.register);3470 try self.truncateRegister(Type.anyerror, result.register);
3116 }3471 }
...@@ -3162,7 +3517,12 @@ fn genUnwrapErrorUnionPayloadMir(...@@ -3162,7 +3517,12 @@ fn genUnwrapErrorUnionPayloadMir(
3162 .{ .register = try self.copyToTmpRegister(err_union_ty, err_union) };3517 .{ .register = try self.copyToTmpRegister(err_union_ty, err_union) };
3163 if (payload_off > 0) {3518 if (payload_off > 0) {
3164 const shift = @intCast(u6, payload_off * 8);3519 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 );
3166 } else {3526 } else {
3167 try self.truncateRegister(payload_ty, result_mcv.register);3527 try self.truncateRegister(payload_ty, result_mcv.register);
3168 }3528 }
...@@ -3199,7 +3559,7 @@ fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3199,7 +3559,7 @@ fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void {
3199 const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*));3559 const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*));
3200 const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*));3560 const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*));
3201 try self.asmRegisterMemory(3561 try self.asmRegisterMemory(
3202 .mov,3562 .{ ._, .mov },
3203 registerAlias(dst_reg, err_abi_size),3563 registerAlias(dst_reg, err_abi_size),
3204 Memory.sib(Memory.PtrSize.fromSize(err_abi_size), .{3564 Memory.sib(Memory.PtrSize.fromSize(err_abi_size), .{
3205 .base = .{ .reg = src_reg },3565 .base = .{ .reg = src_reg },
...@@ -3237,7 +3597,7 @@ fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3237,7 +3597,7 @@ fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
3237 const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, self.target.*));3597 const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, self.target.*));
3238 const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));3598 const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
3239 try self.asmRegisterMemory(3599 try self.asmRegisterMemory(
3240 .lea,3600 .{ ._, .lea },
3241 registerAlias(dst_reg, dst_abi_size),3601 registerAlias(dst_reg, dst_abi_size),
3242 Memory.sib(.qword, .{ .base = .{ .reg = src_reg }, .disp = pl_off }),3602 Memory.sib(.qword, .{ .base = .{ .reg = src_reg }, .disp = pl_off }),
3243 );3603 );
...@@ -3263,7 +3623,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {...@@ -3263,7 +3623,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
3263 const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*));3623 const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*));
3264 const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*));3624 const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*));
3265 try self.asmMemoryImmediate(3625 try self.asmMemoryImmediate(
3266 .mov,3626 .{ ._, .mov },
3267 Memory.sib(Memory.PtrSize.fromSize(err_abi_size), .{3627 Memory.sib(Memory.PtrSize.fromSize(err_abi_size), .{
3268 .base = .{ .reg = src_reg },3628 .base = .{ .reg = src_reg },
3269 .disp = err_off,3629 .disp = err_off,
...@@ -3284,7 +3644,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {...@@ -3284,7 +3644,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
3284 const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, self.target.*));3644 const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, self.target.*));
3285 const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));3645 const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
3286 try self.asmRegisterMemory(3646 try self.asmRegisterMemory(
3287 .lea,3647 .{ ._, .lea },
3288 registerAlias(dst_reg, dst_abi_size),3648 registerAlias(dst_reg, dst_abi_size),
3289 Memory.sib(.qword, .{ .base = .{ .reg = src_reg }, .disp = pl_off }),3649 Memory.sib(.qword, .{ .base = .{ .reg = src_reg }, .disp = pl_off }),
3290 );3650 );
...@@ -3335,13 +3695,13 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {...@@ -3335,13 +3695,13 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
3335 else => unreachable,3695 else => unreachable,
33363696
3337 .register => |opt_reg| try self.asmRegisterImmediate(3697 .register => |opt_reg| try self.asmRegisterImmediate(
3338 .bts,3698 .{ ._s, .bt },
3339 opt_reg,3699 opt_reg,
3340 Immediate.u(@intCast(u6, pl_abi_size * 8)),3700 Immediate.u(@intCast(u6, pl_abi_size * 8)),
3341 ),3701 ),
33423702
3343 .load_frame => |frame_addr| try self.asmMemoryImmediate(3703 .load_frame => |frame_addr| try self.asmMemoryImmediate(
3344 .mov,3704 .{ ._, .mov },
3345 Memory.sib(.byte, .{3705 Memory.sib(.byte, .{
3346 .base = .{ .frame = frame_addr.index },3706 .base = .{ .frame = frame_addr.index },
3347 .disp = frame_addr.off + pl_abi_size,3707 .disp = frame_addr.off + pl_abi_size,
...@@ -3453,7 +3813,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3453,7 +3813,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {
34533813
3454 const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));3814 const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
3455 try self.asmRegisterMemory(3815 try self.asmRegisterMemory(
3456 .lea,3816 .{ ._, .lea },
3457 registerAlias(dst_reg, dst_abi_size),3817 registerAlias(dst_reg, dst_abi_size),
3458 Memory.sib(.qword, .{3818 Memory.sib(.qword, .{
3459 .base = .{ .reg = src_reg },3819 .base = .{ .reg = src_reg },
...@@ -3527,7 +3887,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {...@@ -3527,7 +3887,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
3527 try self.genSetReg(addr_reg, Type.usize, slice_mcv);3887 try self.genSetReg(addr_reg, Type.usize, slice_mcv);
3528 // TODO we could allocate register here, but need to expect addr register and potentially3888 // TODO we could allocate register here, but need to expect addr register and potentially
3529 // offset register.3889 // 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 }, .{
3531 .register = offset_reg,3891 .register = offset_reg,
3532 });3892 });
3533 return MCValue{ .register = addr_reg.to64() };3893 return MCValue{ .register = addr_reg.to64() };
...@@ -3585,13 +3945,13 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -3585,13 +3945,13 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
3585 const frame_index = try self.allocFrameIndex(FrameAlloc.initType(array_ty, self.target.*));3945 const frame_index = try self.allocFrameIndex(FrameAlloc.initType(array_ty, self.target.*));
3586 try self.genSetMem(.{ .frame = frame_index }, 0, array_ty, array);3946 try self.genSetMem(.{ .frame = frame_index }, 0, array_ty, array);
3587 try self.asmRegisterMemory(3947 try self.asmRegisterMemory(
3588 .lea,3948 .{ ._, .lea },
3589 addr_reg,3949 addr_reg,
3590 Memory.sib(.qword, .{ .base = .{ .frame = frame_index } }),3950 Memory.sib(.qword, .{ .base = .{ .frame = frame_index } }),
3591 );3951 );
3592 },3952 },
3593 .load_frame => |frame_addr| try self.asmRegisterMemory(3953 .load_frame => |frame_addr| try self.asmRegisterMemory(
3594 .lea,3954 .{ ._, .lea },
3595 addr_reg,3955 addr_reg,
3596 Memory.sib(.qword, .{ .base = .{ .frame = frame_addr.index }, .disp = frame_addr.off }),3956 Memory.sib(.qword, .{ .base = .{ .frame = frame_addr.index }, .disp = frame_addr.off }),
3597 ),3957 ),
...@@ -3607,7 +3967,12 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -3607,7 +3967,12 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
3607 // TODO we could allocate register here, but need to expect addr register and potentially3967 // TODO we could allocate register here, but need to expect addr register and potentially
3608 // offset register.3968 // offset register.
3609 const dst_mcv = try self.allocRegOrMem(inst, false);3969 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 );
3611 try self.genCopy(elem_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });3976 try self.genCopy(elem_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });
36123977
3613 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });3978 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 {...@@ -3641,7 +4006,11 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
3641 try self.copyToTmpRegister(ptr_ty, ptr_mcv);4006 try self.copyToTmpRegister(ptr_ty, ptr_mcv);
3642 const elem_ptr_lock = self.register_manager.lockRegAssumeUnused(elem_ptr_reg);4007 const elem_ptr_lock = self.register_manager.lockRegAssumeUnused(elem_ptr_reg);
3643 defer self.register_manager.unlockReg(elem_ptr_lock);4008 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
3646 const dst_mcv = try self.allocRegOrMem(inst, true);4015 const dst_mcv = try self.allocRegOrMem(inst, true);
3647 const dst_lock = switch (dst_mcv) {4016 const dst_lock = switch (dst_mcv) {
...@@ -3681,7 +4050,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3681,7 +4050,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
3681 defer self.register_manager.unlockReg(offset_reg_lock);4050 defer self.register_manager.unlockReg(offset_reg_lock);
36824051
3683 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr);4052 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
3686 return self.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none });4055 return self.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none });
3687}4056}
...@@ -3714,7 +4083,12 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {...@@ -3714,7 +4083,12 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
3714 const adjusted_ptr: MCValue = if (layout.payload_size > 0 and layout.tag_align < layout.payload_align) blk: {4083 const adjusted_ptr: MCValue = if (layout.payload_size > 0 and layout.tag_align < layout.payload_align) blk: {
3715 // TODO reusing the operand4084 // TODO reusing the operand
3716 const reg = try self.copyToTmpRegister(ptr_union_ty, ptr);4085 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 );
3718 break :blk MCValue{ .register = reg };4092 break :blk MCValue{ .register = reg };
3719 } else ptr;4093 } else ptr;
37204094
...@@ -3767,7 +4141,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {...@@ -3767,7 +4141,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
3767 else4141 else
3768 0;4142 0;
3769 const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand);4143 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 });
3771 break :blk MCValue{4145 break :blk MCValue{
3772 .register = registerAlias(result.register, @intCast(u32, layout.tag_size)),4146 .register = registerAlias(result.register, @intCast(u32, layout.tag_size)),
3773 };4147 };
...@@ -3798,24 +4172,53 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {...@@ -3798,24 +4172,53 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
37984172
3799 const dst_reg = try self.register_manager.allocReg(inst, gp);4173 const dst_reg = try self.register_manager.allocReg(inst, gp);
3800 const dst_mcv = MCValue{ .register = dst_reg };4174 const dst_mcv = MCValue{ .register = dst_reg };
3801 const dst_lock = self.register_manager.lockReg(dst_reg);4175 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
3802 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);4176 defer self.register_manager.unlockReg(dst_lock);
38034177
3804 if (Target.x86.featureSetHas(self.target.cpu.features, .lzcnt)) {4178 const src_bits = src_ty.bitSize(self.target.*);
3805 try self.genBinOpMir(.lzcnt, src_ty, dst_mcv, mat_src_mcv);4179 if (self.hasFeature(.lzcnt)) {
3806 const extra_bits = self.regExtraBits(src_ty);4180 if (src_bits <= 64) {
3807 if (extra_bits > 0) {4181 try self.genBinOpMir(.{ ._, .lzcnt }, src_ty, dst_mcv, mat_src_mcv);
3808 try self.genBinOpMir(.sub, dst_ty, dst_mcv, .{ .immediate = extra_bits });4182
3809 }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.?)});
3810 break :result dst_mcv;4212 break :result dst_mcv;
3811 }4213 }
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.?)});
3814 if (math.isPowerOfTwo(src_bits)) {4217 if (math.isPowerOfTwo(src_bits)) {
3815 const imm_reg = try self.copyToTmpRegister(dst_ty, .{4218 const imm_reg = try self.copyToTmpRegister(dst_ty, .{
3816 .immediate = src_bits ^ (src_bits - 1),4219 .immediate = src_bits ^ (src_bits - 1),
3817 });4220 });
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
3820 const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);4223 const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);
3821 try self.asmCmovccRegisterRegister(4224 try self.asmCmovccRegisterRegister(
...@@ -3824,12 +4227,12 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {...@@ -3824,12 +4227,12 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
3824 .z,4227 .z,
3825 );4228 );
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 });
3828 } else {4231 } else {
3829 const imm_reg = try self.copyToTmpRegister(dst_ty, .{4232 const imm_reg = try self.copyToTmpRegister(dst_ty, .{
3830 .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - self.regBitSize(dst_ty)),4233 .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - self.regBitSize(dst_ty)),
3831 });4234 });
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
3834 const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);4237 const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);
3835 try self.asmCmovccRegisterRegister(4238 try self.asmCmovccRegisterRegister(
...@@ -3839,7 +4242,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {...@@ -3839,7 +4242,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
3839 );4242 );
38404243
3841 try self.genSetReg(dst_reg, dst_ty, .{ .immediate = src_bits - 1 });4244 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 });
3843 }4246 }
3844 break :result dst_mcv;4247 break :result dst_mcv;
3845 };4248 };
...@@ -3869,27 +4272,55 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {...@@ -3869,27 +4272,55 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
3869 const dst_lock = self.register_manager.lockReg(dst_reg);4272 const dst_lock = self.register_manager.lockReg(dst_reg);
3870 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);4273 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
38714274
3872 if (Target.x86.featureSetHas(self.target.cpu.features, .bmi)) {4275 if (self.hasFeature(.bmi)) {
3873 const extra_bits = self.regExtraBits(src_ty);4276 if (src_bits <= 64) {
3874 const masked_mcv = if (extra_bits > 0) masked: {4277 const extra_bits = self.regExtraBits(src_ty);
3875 const mask_mcv = MCValue{4278 const masked_mcv = if (extra_bits > 0) masked: {
3876 .immediate = ((@as(u64, 1) << @intCast(u6, extra_bits)) - 1) <<4279 const tmp_mcv = tmp: {
3877 @intCast(u6, src_bits),4280 if (src_mcv.isImmediate() or self.liveness.operandDies(inst, 0))
3878 };4281 break :tmp src_mcv;
3879 const tmp_mcv = tmp: {4282 try self.genSetReg(dst_reg, src_ty, src_mcv);
3880 if (src_mcv.isImmediate() or self.liveness.operandDies(inst, 0)) break :tmp src_mcv;4283 break :tmp dst_mcv;
3881 try self.genSetReg(dst_reg, src_ty, src_mcv);4284 };
3882 break :tmp dst_mcv;4285 try self.genBinOpMir(
3883 };4286 .{ ._, .@"or" },
3884 try self.genBinOpMir(.@"or", src_ty, tmp_mcv, mask_mcv);4287 src_ty,
3885 break :masked tmp_mcv;4288 tmp_mcv,
3886 } else mat_src_mcv;4289 .{ .immediate = (@as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - extra_bits)) <<
3887 try self.genBinOpMir(.tzcnt, src_ty, dst_mcv, masked_mcv);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.?)});
3888 break :result dst_mcv;4316 break :result dst_mcv;
3889 }4317 }
38904318
4319 if (src_bits > 64)
4320 return self.fail("TODO airCtz of {}", .{src_ty.fmt(self.bin_file.options.module.?)});
4321
3891 const width_reg = try self.copyToTmpRegister(dst_ty, .{ .immediate = src_bits });4322 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
3894 const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);4325 const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);
3895 try self.asmCmovccRegisterRegister(4326 try self.asmCmovccRegisterRegister(
...@@ -3909,7 +4340,7 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {...@@ -3909,7 +4340,7 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
3909 const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));4340 const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));
3910 const src_mcv = try self.resolveInst(ty_op.operand);4341 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)) {
3913 const mat_src_mcv = switch (src_mcv) {4344 const mat_src_mcv = switch (src_mcv) {
3914 .immediate => MCValue{ .register = try self.copyToTmpRegister(src_ty, src_mcv) },4345 .immediate => MCValue{ .register = try self.copyToTmpRegister(src_ty, src_mcv) },
3915 else => src_mcv,4346 else => src_mcv,
...@@ -3927,7 +4358,7 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {...@@ -3927,7 +4358,7 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
3927 .{ .register = try self.register_manager.allocReg(inst, gp) };4358 .{ .register = try self.register_manager.allocReg(inst, gp) };
39284359
3929 const popcnt_ty = if (src_abi_size > 1) src_ty else Type.u16;4360 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);
3931 break :result dst_mcv;4362 break :result dst_mcv;
3932 }4363 }
39334364
...@@ -3958,54 +4389,54 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {...@@ -3958,54 +4389,54 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
3958 undefined;4389 undefined;
39594390
3960 // dst = operand4391 // dst = operand
3961 try self.asmRegisterRegister(.mov, tmp, dst);4392 try self.asmRegisterRegister(.{ ._, .mov }, tmp, dst);
3962 // tmp = operand4393 // tmp = operand
3963 try self.asmRegisterImmediate(.shr, tmp, Immediate.u(1));4394 try self.asmRegisterImmediate(.{ ._r, .sh }, tmp, Immediate.u(1));
3964 // tmp = operand >> 14395 // tmp = operand >> 1
3965 if (src_abi_size > 4) {4396 if (src_abi_size > 4) {
3966 try self.asmRegisterImmediate(.mov, imm, imm_0_1);4397 try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_0_1);
3967 try self.asmRegisterRegister(.@"and", tmp, imm);4398 try self.asmRegisterRegister(.{ ._, .@"and" }, tmp, imm);
3968 } else try self.asmRegisterImmediate(.@"and", tmp, imm_0_1);4399 } else try self.asmRegisterImmediate(.{ ._, .@"and" }, tmp, imm_0_1);
3969 // tmp = (operand >> 1) & 0x55...554400 // tmp = (operand >> 1) & 0x55...55
3970 try self.asmRegisterRegister(.sub, dst, tmp);4401 try self.asmRegisterRegister(.{ ._, .sub }, dst, tmp);
3971 // dst = temp1 = operand - ((operand >> 1) & 0x55...55)4402 // dst = temp1 = operand - ((operand >> 1) & 0x55...55)
3972 try self.asmRegisterRegister(.mov, tmp, dst);4403 try self.asmRegisterRegister(.{ ._, .mov }, tmp, dst);
3973 // tmp = temp14404 // tmp = temp1
3974 try self.asmRegisterImmediate(.shr, dst, Immediate.u(2));4405 try self.asmRegisterImmediate(.{ ._r, .sh }, dst, Immediate.u(2));
3975 // dst = temp1 >> 24406 // dst = temp1 >> 2
3976 if (src_abi_size > 4) {4407 if (src_abi_size > 4) {
3977 try self.asmRegisterImmediate(.mov, imm, imm_00_11);4408 try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_00_11);
3978 try self.asmRegisterRegister(.@"and", tmp, imm);4409 try self.asmRegisterRegister(.{ ._, .@"and" }, tmp, imm);
3979 try self.asmRegisterRegister(.@"and", dst, imm);4410 try self.asmRegisterRegister(.{ ._, .@"and" }, dst, imm);
3980 } else {4411 } else {
3981 try self.asmRegisterImmediate(.@"and", tmp, imm_00_11);4412 try self.asmRegisterImmediate(.{ ._, .@"and" }, tmp, imm_00_11);
3982 try self.asmRegisterImmediate(.@"and", dst, imm_00_11);4413 try self.asmRegisterImmediate(.{ ._, .@"and" }, dst, imm_00_11);
3983 }4414 }
3984 // tmp = temp1 & 0x33...334415 // tmp = temp1 & 0x33...33
3985 // dst = (temp1 >> 2) & 0x33...334416 // dst = (temp1 >> 2) & 0x33...33
3986 try self.asmRegisterRegister(.add, tmp, dst);4417 try self.asmRegisterRegister(.{ ._, .add }, tmp, dst);
3987 // tmp = temp2 = (temp1 & 0x33...33) + ((temp1 >> 2) & 0x33...33)4418 // tmp = temp2 = (temp1 & 0x33...33) + ((temp1 >> 2) & 0x33...33)
3988 try self.asmRegisterRegister(.mov, dst, tmp);4419 try self.asmRegisterRegister(.{ ._, .mov }, dst, tmp);
3989 // dst = temp24420 // dst = temp2
3990 try self.asmRegisterImmediate(.shr, tmp, Immediate.u(4));4421 try self.asmRegisterImmediate(.{ ._r, .sh }, tmp, Immediate.u(4));
3991 // tmp = temp2 >> 44422 // tmp = temp2 >> 4
3992 try self.asmRegisterRegister(.add, dst, tmp);4423 try self.asmRegisterRegister(.{ ._, .add }, dst, tmp);
3993 // dst = temp2 + (temp2 >> 4)4424 // dst = temp2 + (temp2 >> 4)
3994 if (src_abi_size > 4) {4425 if (src_abi_size > 4) {
3995 try self.asmRegisterImmediate(.mov, imm, imm_0000_1111);4426 try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_0000_1111);
3996 try self.asmRegisterImmediate(.mov, tmp, imm_0000_0001);4427 try self.asmRegisterImmediate(.{ ._, .mov }, tmp, imm_0000_0001);
3997 try self.asmRegisterRegister(.@"and", dst, imm);4428 try self.asmRegisterRegister(.{ ._, .@"and" }, dst, imm);
3998 try self.asmRegisterRegister(.imul, dst, tmp);4429 try self.asmRegisterRegister(.{ .i_, .mul }, dst, tmp);
3999 } else {4430 } else {
4000 try self.asmRegisterImmediate(.@"and", dst, imm_0000_1111);4431 try self.asmRegisterImmediate(.{ ._, .@"and" }, dst, imm_0000_1111);
4001 if (src_abi_size > 1) {4432 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);
4003 }4434 }
4004 }4435 }
4005 // dst = temp3 = (temp2 + (temp2 >> 4)) & 0x0f...0f4436 // dst = temp3 = (temp2 + (temp2 >> 4)) & 0x0f...0f
4006 // dst = temp3 * 0x01...014437 // dst = temp3 * 0x01...01
4007 if (src_abi_size > 1) {4438 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));
4009 }4440 }
4010 // dst = (temp3 * 0x01...01) >> (bits - 8)4441 // dst = (temp3 * 0x01...01) >> (bits - 8)
4011 }4442 }
...@@ -4034,11 +4465,11 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m...@@ -4034,11 +4465,11 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m
4034 16 => if ((mem_ok or src_mcv.isRegister()) and4465 16 => if ((mem_ok or src_mcv.isRegister()) and
4035 self.reuseOperand(inst, ty_op.operand, 0, src_mcv))4466 self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
4036 {4467 {
4037 try self.genBinOpMir(.rol, src_ty, src_mcv, .{ .immediate = 8 });4468 try self.genBinOpMir(.{ ._l, .ro }, src_ty, src_mcv, .{ .immediate = 8 });
4038 return src_mcv;4469 return src_mcv;
4039 },4470 },
4040 32, 64 => if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) {4471 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);
4042 return src_mcv;4473 return src_mcv;
4043 },4474 },
4044 }4475 }
...@@ -4055,10 +4486,10 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m...@@ -4055,10 +4486,10 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m
4055 try self.genSetReg(dst_mcv.register, src_ty, src_mcv);4486 try self.genSetReg(dst_mcv.register, src_ty, src_mcv);
4056 switch (src_bits) {4487 switch (src_bits) {
4057 else => unreachable,4488 else => unreachable,
4058 16 => try self.genBinOpMir(.rol, src_ty, dst_mcv, .{ .immediate = 8 }),4489 16 => try self.genBinOpMir(.{ ._l, .ro }, src_ty, dst_mcv, .{ .immediate = 8 }),
4059 32, 64 => try self.genUnOpMir(.bswap, src_ty, dst_mcv),4490 32, 64 => try self.genUnOpMir(.{ ._, .bswap }, src_ty, dst_mcv),
4060 }4491 }
4061 } else try self.genBinOpMir(.movbe, src_ty, dst_mcv, src_mcv);4492 } else try self.genBinOpMir(.{ ._, .movbe }, src_ty, dst_mcv, src_mcv);
4062 return dst_mcv;4493 return dst_mcv;
4063 }4494 }
40644495
...@@ -4067,7 +4498,7 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m...@@ -4067,7 +4498,7 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m
4067 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);4498 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
4068 defer self.register_manager.unlockReg(dst_lock);4499 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);
4071 return dst_mcv;4502 return dst_mcv;
4072}4503}
40734504
...@@ -4081,7 +4512,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {...@@ -4081,7 +4512,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
4081 switch (self.regExtraBits(src_ty)) {4512 switch (self.regExtraBits(src_ty)) {
4082 0 => {},4513 0 => {},
4083 else => |extra| try self.genBinOpMir(4514 else => |extra| try self.genBinOpMir(
4084 if (src_ty.isSignedInt()) .sar else .shr,4515 if (src_ty.isSignedInt()) .{ ._r, .sa } else .{ ._r, .sh },
4085 src_ty,4516 src_ty,
4086 dst_mcv,4517 dst_mcv,
4087 .{ .immediate = extra },4518 .{ .immediate = extra },
...@@ -4121,40 +4552,40 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {...@@ -4121,40 +4552,40 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
4121 const imm_0_1 = Immediate.u(mask / 0b1_1);4552 const imm_0_1 = Immediate.u(mask / 0b1_1);
41224553
4123 // dst = temp1 = bswap(operand)4554 // dst = temp1 = bswap(operand)
4124 try self.asmRegisterRegister(.mov, tmp, dst);4555 try self.asmRegisterRegister(.{ ._, .mov }, tmp, dst);
4125 // tmp = temp14556 // tmp = temp1
4126 try self.asmRegisterImmediate(.shr, dst, Immediate.u(4));4557 try self.asmRegisterImmediate(.{ ._r, .sh }, dst, Immediate.u(4));
4127 // dst = temp1 >> 44558 // dst = temp1 >> 4
4128 if (src_abi_size > 4) {4559 if (src_abi_size > 4) {
4129 try self.asmRegisterImmediate(.mov, imm, imm_0000_1111);4560 try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_0000_1111);
4130 try self.asmRegisterRegister(.@"and", tmp, imm);4561 try self.asmRegisterRegister(.{ ._, .@"and" }, tmp, imm);
4131 try self.asmRegisterRegister(.@"and", dst, imm);4562 try self.asmRegisterRegister(.{ ._, .@"and" }, dst, imm);
4132 } else {4563 } else {
4133 try self.asmRegisterImmediate(.@"and", tmp, imm_0000_1111);4564 try self.asmRegisterImmediate(.{ ._, .@"and" }, tmp, imm_0000_1111);
4134 try self.asmRegisterImmediate(.@"and", dst, imm_0000_1111);4565 try self.asmRegisterImmediate(.{ ._, .@"and" }, dst, imm_0000_1111);
4135 }4566 }
4136 // tmp = temp1 & 0x0F...0F4567 // tmp = temp1 & 0x0F...0F
4137 // dst = (temp1 >> 4) & 0x0F...0F4568 // dst = (temp1 >> 4) & 0x0F...0F
4138 try self.asmRegisterImmediate(.shl, tmp, Immediate.u(4));4569 try self.asmRegisterImmediate(.{ ._l, .sh }, tmp, Immediate.u(4));
4139 // tmp = (temp1 & 0x0F...0F) << 44570 // tmp = (temp1 & 0x0F...0F) << 4
4140 try self.asmRegisterRegister(.@"or", dst, tmp);4571 try self.asmRegisterRegister(.{ ._, .@"or" }, dst, tmp);
4141 // dst = temp2 = ((temp1 >> 4) & 0x0F...0F) | ((temp1 & 0x0F...0F) << 4)4572 // dst = temp2 = ((temp1 >> 4) & 0x0F...0F) | ((temp1 & 0x0F...0F) << 4)
4142 try self.asmRegisterRegister(.mov, tmp, dst);4573 try self.asmRegisterRegister(.{ ._, .mov }, tmp, dst);
4143 // tmp = temp24574 // tmp = temp2
4144 try self.asmRegisterImmediate(.shr, dst, Immediate.u(2));4575 try self.asmRegisterImmediate(.{ ._r, .sh }, dst, Immediate.u(2));
4145 // dst = temp2 >> 24576 // dst = temp2 >> 2
4146 if (src_abi_size > 4) {4577 if (src_abi_size > 4) {
4147 try self.asmRegisterImmediate(.mov, imm, imm_00_11);4578 try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_00_11);
4148 try self.asmRegisterRegister(.@"and", tmp, imm);4579 try self.asmRegisterRegister(.{ ._, .@"and" }, tmp, imm);
4149 try self.asmRegisterRegister(.@"and", dst, imm);4580 try self.asmRegisterRegister(.{ ._, .@"and" }, dst, imm);
4150 } else {4581 } else {
4151 try self.asmRegisterImmediate(.@"and", tmp, imm_00_11);4582 try self.asmRegisterImmediate(.{ ._, .@"and" }, tmp, imm_00_11);
4152 try self.asmRegisterImmediate(.@"and", dst, imm_00_11);4583 try self.asmRegisterImmediate(.{ ._, .@"and" }, dst, imm_00_11);
4153 }4584 }
4154 // tmp = temp2 & 0x33...334585 // tmp = temp2 & 0x33...33
4155 // dst = (temp2 >> 2) & 0x33...334586 // dst = (temp2 >> 2) & 0x33...33
4156 try self.asmRegisterMemory(4587 try self.asmRegisterMemory(
4157 .lea,4588 .{ ._, .lea },
4158 if (src_abi_size > 4) tmp.to64() else tmp.to32(),4589 if (src_abi_size > 4) tmp.to64() else tmp.to32(),
4159 Memory.sib(.qword, .{4590 Memory.sib(.qword, .{
4160 .base = .{ .reg = dst.to64() },4591 .base = .{ .reg = dst.to64() },
...@@ -4162,22 +4593,22 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {...@@ -4162,22 +4593,22 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
4162 }),4593 }),
4163 );4594 );
4164 // tmp = temp3 = ((temp2 >> 2) & 0x33...33) + ((temp2 & 0x33...33) << 2)4595 // tmp = temp3 = ((temp2 >> 2) & 0x33...33) + ((temp2 & 0x33...33) << 2)
4165 try self.asmRegisterRegister(.mov, dst, tmp);4596 try self.asmRegisterRegister(.{ ._, .mov }, dst, tmp);
4166 // dst = temp34597 // dst = temp3
4167 try self.asmRegisterImmediate(.shr, tmp, Immediate.u(1));4598 try self.asmRegisterImmediate(.{ ._r, .sh }, tmp, Immediate.u(1));
4168 // tmp = temp3 >> 14599 // tmp = temp3 >> 1
4169 if (src_abi_size > 4) {4600 if (src_abi_size > 4) {
4170 try self.asmRegisterImmediate(.mov, imm, imm_0_1);4601 try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_0_1);
4171 try self.asmRegisterRegister(.@"and", dst, imm);4602 try self.asmRegisterRegister(.{ ._, .@"and" }, dst, imm);
4172 try self.asmRegisterRegister(.@"and", tmp, imm);4603 try self.asmRegisterRegister(.{ ._, .@"and" }, tmp, imm);
4173 } else {4604 } else {
4174 try self.asmRegisterImmediate(.@"and", dst, imm_0_1);4605 try self.asmRegisterImmediate(.{ ._, .@"and" }, dst, imm_0_1);
4175 try self.asmRegisterImmediate(.@"and", tmp, imm_0_1);4606 try self.asmRegisterImmediate(.{ ._, .@"and" }, tmp, imm_0_1);
4176 }4607 }
4177 // dst = temp3 & 0x55...554608 // dst = temp3 & 0x55...55
4178 // tmp = (temp3 >> 1) & 0x55...554609 // tmp = (temp3 >> 1) & 0x55...55
4179 try self.asmRegisterMemory(4610 try self.asmRegisterMemory(
4180 .lea,4611 .{ ._, .lea },
4181 if (src_abi_size > 4) dst.to64() else dst.to32(),4612 if (src_abi_size > 4) dst.to64() else dst.to32(),
4182 Memory.sib(.qword, .{4613 Memory.sib(.qword, .{
4183 .base = .{ .reg = tmp.to64() },4614 .base = .{ .reg = tmp.to64() },
...@@ -4190,7 +4621,7 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {...@@ -4190,7 +4621,7 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
4190 switch (self.regExtraBits(src_ty)) {4621 switch (self.regExtraBits(src_ty)) {
4191 0 => {},4622 0 => {},
4192 else => |extra| try self.genBinOpMir(4623 else => |extra| try self.genBinOpMir(
4193 if (src_ty.isSignedInt()) .sar else .shr,4624 if (src_ty.isSignedInt()) .{ ._r, .sa } else .{ ._r, .sh },
4194 src_ty,4625 src_ty,
4195 dst_mcv,4626 dst_mcv,
4196 .{ .immediate = extra },4627 .{ .immediate = extra },
...@@ -4246,19 +4677,20 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {...@@ -4246,19 +4677,20 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {
4246 const tag = self.air.instructions.items(.tag)[inst];4677 const tag = self.air.instructions.items(.tag)[inst];
4247 try self.genBinOpMir(switch (ty_bits) {4678 try self.genBinOpMir(switch (ty_bits) {
4248 // No point using an extra prefix byte for *pd which performs the same operation.4679 // No point using an extra prefix byte for *pd which performs the same operation.
4249 32, 64 => switch (tag) {4680 16, 32, 64, 128 => switch (tag) {
4250 .neg => .xorps,4681 .neg => .{ ._ps, .xor },
4251 .fabs => .andnps,4682 .fabs => .{ ._ps, .andn },
4252 else => unreachable,4683 else => unreachable,
4253 },4684 },
4254 else => return self.fail("TODO implement airFloatSign for {}", .{4685 80 => return self.fail("TODO implement airFloatSign for {}", .{
4255 ty.fmt(self.bin_file.options.module.?),4686 ty.fmt(self.bin_file.options.module.?),
4256 }),4687 }),
4688 else => unreachable,
4257 }, vec_ty, dst_mcv, sign_mcv);4689 }, vec_ty, dst_mcv, sign_mcv);
4258 return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none });4690 return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none });
4259}4691}
42604692
4261fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {4693fn airRound(self: *Self, inst: Air.Inst.Index, mode: u4) !void {
4262 const un_op = self.air.instructions.items(.data)[inst].un_op;4694 const un_op = self.air.instructions.items(.data)[inst].un_op;
4263 const ty = self.air.typeOf(un_op);4695 const ty = self.air.typeOf(un_op);
42644696
...@@ -4267,40 +4699,246 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {...@@ -4267,40 +4699,246 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
4267 src_mcv4699 src_mcv
4268 else4700 else
4269 try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);4701 try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
42704702 const dst_reg = dst_mcv.getReg().?;
4271 try self.genBinOpMir(switch (ty.zigTypeTag()) {4703 const dst_lock = self.register_manager.lockReg(dst_reg);
4272 .Float => switch (ty.floatBits(self.target.*)) {4704 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
4273 32 => .sqrtss,4705 try self.genRound(ty, dst_reg, src_mcv, mode);
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);
4283 return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none });4706 return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none });
4284}4707}
42854708
4286fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {4709fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4) !void {
4287 const un_op = self.air.instructions.items(.data)[inst].un_op;4710 if (!self.hasFeature(.sse4_1))
4288 _ = un_op;4711 return self.fail("TODO implement genRound without sse4_1 feature", .{});
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}
42944712
4295fn reuseOperand(4713 const mir_tag = if (@as(?Mir.Inst.FixedTag, switch (ty.zigTypeTag()) {
4296 self: *Self,4714 .Float => switch (ty.floatBits(self.target.*)) {
4297 inst: Air.Inst.Index,4715 32 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round },
4298 operand: Air.Inst.Ref,4716 64 => if (self.hasFeature(.avx)) .{ .v_sd, .round } else .{ ._sd, .round },
4299 op_index: Liveness.OperandInt,4717 16, 80, 128 => null,
4300 mcv: MCValue,4718 else => unreachable,
4301) bool {4719 },
4302 return self.reuseOperandAdvanced(inst, operand, op_index, mcv, inst);4720 .Vector => switch (ty.childType().zigTypeTag()) {
4303}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
4305fn reuseOperandAdvanced(4943fn reuseOperandAdvanced(
4306 self: *Self,4944 self: *Self,
...@@ -4366,14 +5004,14 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn...@@ -4366,14 +5004,14 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn
4366 if (load_abi_size <= 8) {5004 if (load_abi_size <= 8) {
4367 const load_reg = registerAlias(dst_reg, load_abi_size);5005 const load_reg = registerAlias(dst_reg, load_abi_size);
4368 try self.asmRegisterMemory(5006 try self.asmRegisterMemory(
4369 .mov,5007 .{ ._, .mov },
4370 load_reg,5008 load_reg,
4371 Memory.sib(Memory.PtrSize.fromSize(load_abi_size), .{5009 Memory.sib(Memory.PtrSize.fromSize(load_abi_size), .{
4372 .base = .{ .reg = ptr_reg },5010 .base = .{ .reg = ptr_reg },
4373 .disp = val_byte_off,5011 .disp = val_byte_off,
4374 }),5012 }),
4375 );5013 );
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));
4377 } else {5015 } else {
4378 const tmp_reg = registerAlias(try self.register_manager.allocReg(null, gp), val_abi_size);5016 const tmp_reg = registerAlias(try self.register_manager.allocReg(null, gp), val_abi_size);
4379 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);5017 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...@@ -4381,7 +5019,7 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn
43815019
4382 const dst_alias = registerAlias(dst_reg, val_abi_size);5020 const dst_alias = registerAlias(dst_reg, val_abi_size);
4383 try self.asmRegisterMemory(5021 try self.asmRegisterMemory(
4384 .mov,5022 .{ ._, .mov },
4385 dst_alias,5023 dst_alias,
4386 Memory.sib(Memory.PtrSize.fromSize(val_abi_size), .{5024 Memory.sib(Memory.PtrSize.fromSize(val_abi_size), .{
4387 .base = .{ .reg = ptr_reg },5025 .base = .{ .reg = ptr_reg },
...@@ -4389,14 +5027,19 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn...@@ -4389,14 +5027,19 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn
4389 }),5027 }),
4390 );5028 );
4391 try self.asmRegisterMemory(5029 try self.asmRegisterMemory(
4392 .mov,5030 .{ ._, .mov },
4393 tmp_reg,5031 tmp_reg,
4394 Memory.sib(Memory.PtrSize.fromSize(val_abi_size), .{5032 Memory.sib(Memory.PtrSize.fromSize(val_abi_size), .{
4395 .base = .{ .reg = ptr_reg },5033 .base = .{ .reg = ptr_reg },
4396 .disp = val_byte_off + 1,5034 .disp = val_byte_off + 1,
4397 }),5035 }),
4398 );5036 );
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 );
4400 }5043 }
44015044
4402 if (val_extra_bits > 0) try self.truncateRegister(val_ty, dst_reg);5045 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...@@ -4502,13 +5145,13 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In
4502 const part_mask_not = part_mask ^5145 const part_mask_not = part_mask ^
4503 (@as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - limb_abi_bits));5146 (@as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - limb_abi_bits));
4504 if (limb_abi_size <= 4) {5147 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));
4506 } else if (math.cast(i32, @bitCast(i64, part_mask_not))) |small| {5149 } 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));
4508 } else {5151 } else {
4509 const part_mask_reg = try self.register_manager.allocReg(null, gp);5152 const part_mask_reg = try self.register_manager.allocReg(null, gp);
4510 try self.asmRegisterImmediate(.mov, part_mask_reg, Immediate.u(part_mask_not));5153 try self.asmRegisterImmediate(.{ ._, .mov }, part_mask_reg, Immediate.u(part_mask_not));
4511 try self.asmMemoryRegister(.@"and", limb_mem, part_mask_reg);5154 try self.asmMemoryRegister(.{ ._, .@"and" }, limb_mem, part_mask_reg);
4512 }5155 }
45135156
4514 if (src_bit_size <= 64) {5157 if (src_bit_size <= 64) {
...@@ -4519,14 +5162,26 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In...@@ -4519,14 +5162,26 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In
45195162
4520 try self.genSetReg(tmp_reg, src_ty, src_mcv);5163 try self.genSetReg(tmp_reg, src_ty, src_mcv);
4521 switch (limb_i) {5164 switch (limb_i) {
4522 0 => try self.genShiftBinOpMir(.shl, src_ty, tmp_mcv, .{ .immediate = src_bit_off }),5165 0 => try self.genShiftBinOpMir(
4523 1 => try self.genShiftBinOpMir(.shr, src_ty, tmp_mcv, .{5166 .{ ._l, .sh },
4524 .immediate = limb_abi_bits - src_bit_off,5167 src_ty,
4525 }),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 ),
4526 else => unreachable,5177 else => unreachable,
4527 }5178 }
4528 try self.genBinOpMir(.@"and", src_ty, tmp_mcv, .{ .immediate = part_mask });5179 try self.genBinOpMir(.{ ._, .@"and" }, src_ty, tmp_mcv, .{ .immediate = part_mask });
4529 try self.asmMemoryRegister(.@"or", limb_mem, registerAlias(tmp_reg, limb_abi_size));5180 try self.asmMemoryRegister(
5181 .{ ._, .@"or" },
5182 limb_mem,
5183 registerAlias(tmp_reg, limb_abi_size),
5184 );
4530 } else return self.fail("TODO: implement packed store of {}", .{5185 } else return self.fail("TODO: implement packed store of {}", .{
4531 src_ty.fmt(self.bin_file.options.module.?),5186 src_ty.fmt(self.bin_file.options.module.?),
4532 });5187 });
...@@ -4626,7 +5281,7 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32...@@ -4626,7 +5281,7 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32
4626 .load_tlv => |sym_index| .{ .lea_tlv = sym_index },5281 .load_tlv => |sym_index| .{ .lea_tlv = sym_index },
4627 else => mcv,5282 else => mcv,
4628 });5283 });
4629 try self.genBinOpMir(.add, Type.usize, dst_mcv, .{ .register = offset_reg });5284 try self.genBinOpMir(.{ ._, .add }, Type.usize, dst_mcv, .{ .register = offset_reg });
4630 break :result dst_mcv;5285 break :result dst_mcv;
4631 },5286 },
4632 .indirect => |reg_off| break :result .{ .indirect = .{5287 .indirect => |reg_off| break :result .{ .indirect = .{
...@@ -4710,14 +5365,14 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -4710,14 +5365,14 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
4710 if (load_abi_size <= 8) {5365 if (load_abi_size <= 8) {
4711 const load_reg = registerAlias(dst_reg, load_abi_size);5366 const load_reg = registerAlias(dst_reg, load_abi_size);
4712 try self.asmRegisterMemory(5367 try self.asmRegisterMemory(
4713 .mov,5368 .{ ._, .mov },
4714 load_reg,5369 load_reg,
4715 Memory.sib(Memory.PtrSize.fromSize(load_abi_size), .{5370 Memory.sib(Memory.PtrSize.fromSize(load_abi_size), .{
4716 .base = .{ .frame = frame_addr.index },5371 .base = .{ .frame = frame_addr.index },
4717 .disp = frame_addr.off + field_byte_off,5372 .disp = frame_addr.off + field_byte_off,
4718 }),5373 }),
4719 );5374 );
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));
4721 } else {5376 } else {
4722 const tmp_reg = registerAlias(5377 const tmp_reg = registerAlias(
4723 try self.register_manager.allocReg(null, gp),5378 try self.register_manager.allocReg(null, gp),
...@@ -4728,7 +5383,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -4728,7 +5383,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
47285383
4729 const dst_alias = registerAlias(dst_reg, field_abi_size);5384 const dst_alias = registerAlias(dst_reg, field_abi_size);
4730 try self.asmRegisterMemory(5385 try self.asmRegisterMemory(
4731 .mov,5386 .{ ._, .mov },
4732 dst_alias,5387 dst_alias,
4733 Memory.sib(Memory.PtrSize.fromSize(field_abi_size), .{5388 Memory.sib(Memory.PtrSize.fromSize(field_abi_size), .{
4734 .base = .{ .frame = frame_addr.index },5389 .base = .{ .frame = frame_addr.index },
...@@ -4736,7 +5391,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -4736,7 +5391,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
4736 }),5391 }),
4737 );5392 );
4738 try self.asmRegisterMemory(5393 try self.asmRegisterMemory(
4739 .mov,5394 .{ ._, .mov },
4740 tmp_reg,5395 tmp_reg,
4741 Memory.sib(Memory.PtrSize.fromSize(field_abi_size), .{5396 Memory.sib(Memory.PtrSize.fromSize(field_abi_size), .{
4742 .base = .{ .frame = frame_addr.index },5397 .base = .{ .frame = frame_addr.index },
...@@ -4744,7 +5399,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -4744,7 +5399,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
4744 }),5399 }),
4745 );5400 );
4746 try self.asmRegisterRegisterImmediate(5401 try self.asmRegisterRegisterImmediate(
4747 .shrd,5402 .{ ._rd, .sh },
4748 dst_alias,5403 dst_alias,
4749 tmp_reg,5404 tmp_reg,
4750 Immediate.u(field_bit_off),5405 Immediate.u(field_bit_off),
...@@ -4752,7 +5407,14 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -4752,7 +5407,14 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
4752 }5407 }
47535408
4754 if (field_extra_bits > 0) try self.truncateRegister(field_ty, dst_reg);5409 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 };
4756 },5418 },
4757 .register => |reg| {5419 .register => |reg| {
4758 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);5420 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
...@@ -4773,21 +5435,26 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -4773,21 +5435,26 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
4773 defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);5435 defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
47745436
4775 // Shift by struct_field_offset.5437 // 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
4778 // Mask to field_bit_size bits5445 // Mask to field_bit_size bits
4779 const field_bit_size = field_ty.bitSize(self.target.*);5446 const field_bit_size = field_ty.bitSize(self.target.*);
4780 const mask = ~@as(u64, 0) >> @intCast(u6, 64 - field_bit_size);5447 const mask = ~@as(u64, 0) >> @intCast(u6, 64 - field_bit_size);
47815448
4782 const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask });5449 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
4785 const signedness =5452 const signedness =
4786 if (field_ty.isAbiInt()) field_ty.intInfo(self.target.*).signedness else .unsigned;5453 if (field_ty.isAbiInt()) field_ty.intInfo(self.target.*).signedness else .unsigned;
4787 const field_byte_size = @intCast(u32, field_ty.abiSize(self.target.*));5454 const field_byte_size = @intCast(u32, field_ty.abiSize(self.target.*));
4788 if (signedness == .signed and field_byte_size < 8) {5455 if (signedness == .signed and field_byte_size < 8) {
4789 try self.asmRegisterRegister(5456 try self.asmRegisterRegister(
4790 .movsx,5457 if (field_byte_size >= 4) .{ ._d, .movsx } else .{ ._, .movsx },
4791 dst_mcv.register,5458 dst_mcv.register,
4792 registerAlias(dst_mcv.register, field_byte_size),5459 registerAlias(dst_mcv.register, field_byte_size),
4793 );5460 );
...@@ -4899,17 +5566,17 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:...@@ -4899,17 +5566,17 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:
48995566
4900 if (limb_pl.base.tag == .int_unsigned and self.regExtraBits(limb_ty) > 0) {5567 if (limb_pl.base.tag == .int_unsigned and self.regExtraBits(limb_ty) > 0) {
4901 const mask = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - limb_pl.data);5568 const mask = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - limb_pl.data);
4902 try self.genBinOpMir(.xor, limb_ty, limb_mcv, .{ .immediate = mask });5569 try self.genBinOpMir(.{ ._, .xor }, limb_ty, limb_mcv, .{ .immediate = mask });
4903 } else try self.genUnOpMir(.not, limb_ty, limb_mcv);5570 } else try self.genUnOpMir(.{ ._, .not }, limb_ty, limb_mcv);
4904 }5571 }
4905 },5572 },
4906 .neg => try self.genUnOpMir(.neg, src_ty, dst_mcv),5573 .neg => try self.genUnOpMir(.{ ._, .neg }, src_ty, dst_mcv),
4907 else => unreachable,5574 else => unreachable,
4908 }5575 }
4909 return dst_mcv;5576 return dst_mcv;
4910}5577}
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 {
4913 const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));5580 const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
4914 if (abi_size > 8) return self.fail("TODO implement {} for {}", .{5581 if (abi_size > 8) return self.fail("TODO implement {} for {}", .{
4915 mir_tag,5582 mir_tag,
...@@ -4952,7 +5619,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue...@@ -4952,7 +5619,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue
4952/// Clobbers .rcx for non-immediate shift value.5619/// Clobbers .rcx for non-immediate shift value.
4953fn genShiftBinOpMir(5620fn genShiftBinOpMir(
4954 self: *Self,5621 self: *Self,
4955 tag: Mir.Inst.Tag,5622 tag: Mir.Inst.FixedTag,
4956 ty: Type,5623 ty: Type,
4957 lhs_mcv: MCValue,5624 lhs_mcv: MCValue,
4958 shift_mcv: MCValue,5625 shift_mcv: MCValue,
...@@ -5037,16 +5704,16 @@ fn genShiftBinOpMir(...@@ -5037,16 +5704,16 @@ fn genShiftBinOpMir(
5037 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);5704 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
5038 defer self.register_manager.unlockReg(tmp_lock);5705 defer self.register_manager.unlockReg(tmp_lock);
50395706
5040 const info: struct { offsets: [2]i32, double_tag: Mir.Inst.Tag } = switch (tag) {5707 const info: struct { offsets: [2]i32, double_tag: Mir.Inst.FixedTag } = switch (tag[0]) {
5041 .shl, .sal => .{ .offsets = .{ 0, 8 }, .double_tag = .shld },5708 ._l => .{ .offsets = .{ 0, 8 }, .double_tag = .{ ._ld, .sh } },
5042 .shr, .sar => .{ .offsets = .{ 8, 0 }, .double_tag = .shrd },5709 ._r => .{ .offsets = .{ 8, 0 }, .double_tag = .{ ._rd, .sh } },
5043 else => unreachable,5710 else => unreachable,
5044 };5711 };
5045 switch (lhs_mcv) {5712 switch (lhs_mcv) {
5046 .load_frame => |dst_frame_addr| switch (rhs_mcv) {5713 .load_frame => |dst_frame_addr| switch (rhs_mcv) {
5047 .immediate => |rhs_imm| if (rhs_imm == 0) {} else if (rhs_imm < 64) {5714 .immediate => |rhs_imm| if (rhs_imm == 0) {} else if (rhs_imm < 64) {
5048 try self.asmRegisterMemory(5715 try self.asmRegisterMemory(
5049 .mov,5716 .{ ._, .mov },
5050 tmp_reg,5717 tmp_reg,
5051 Memory.sib(.qword, .{5718 Memory.sib(.qword, .{
5052 .base = .{ .frame = dst_frame_addr.index },5719 .base = .{ .frame = dst_frame_addr.index },
...@@ -5073,7 +5740,7 @@ fn genShiftBinOpMir(...@@ -5073,7 +5740,7 @@ fn genShiftBinOpMir(
5073 } else {5740 } else {
5074 assert(rhs_imm < 128);5741 assert(rhs_imm < 128);
5075 try self.asmRegisterMemory(5742 try self.asmRegisterMemory(
5076 .mov,5743 .{ ._, .mov },
5077 tmp_reg,5744 tmp_reg,
5078 Memory.sib(.qword, .{5745 Memory.sib(.qword, .{
5079 .base = .{ .frame = dst_frame_addr.index },5746 .base = .{ .frame = dst_frame_addr.index },
...@@ -5084,34 +5751,30 @@ fn genShiftBinOpMir(...@@ -5084,34 +5751,30 @@ fn genShiftBinOpMir(
5084 try self.asmRegisterImmediate(tag, tmp_reg, Immediate.u(rhs_imm - 64));5751 try self.asmRegisterImmediate(tag, tmp_reg, Immediate.u(rhs_imm - 64));
5085 }5752 }
5086 try self.asmMemoryRegister(5753 try self.asmMemoryRegister(
5087 .mov,5754 .{ ._, .mov },
5088 Memory.sib(.qword, .{5755 Memory.sib(.qword, .{
5089 .base = .{ .frame = dst_frame_addr.index },5756 .base = .{ .frame = dst_frame_addr.index },
5090 .disp = dst_frame_addr.off + info.offsets[1],5757 .disp = dst_frame_addr.off + info.offsets[1],
5091 }),5758 }),
5092 tmp_reg,5759 tmp_reg,
5093 );5760 );
5094 switch (tag) {5761 if (tag[0] == ._r and tag[1] == .sa) try self.asmMemoryImmediate(
5095 .shl, .sal, .shr => {5762 tag,
5096 try self.asmRegisterRegister(.xor, tmp_reg.to32(), tmp_reg.to32());5763 Memory.sib(.qword, .{
5097 try self.asmMemoryRegister(5764 .base = .{ .frame = dst_frame_addr.index },
5098 .mov,5765 .disp = dst_frame_addr.off + info.offsets[0],
5099 Memory.sib(.qword, .{5766 }),
5100 .base = .{ .frame = dst_frame_addr.index },5767 Immediate.u(63),
5101 .disp = dst_frame_addr.off + info.offsets[0],5768 ) else {
5102 }),5769 try self.asmRegisterRegister(.{ ._, .xor }, tmp_reg.to32(), tmp_reg.to32());
5103 tmp_reg,5770 try self.asmMemoryRegister(
5104 );5771 .{ ._, .mov },
5105 },
5106 .sar => try self.asmMemoryImmediate(
5107 tag,
5108 Memory.sib(.qword, .{5772 Memory.sib(.qword, .{
5109 .base = .{ .frame = dst_frame_addr.index },5773 .base = .{ .frame = dst_frame_addr.index },
5110 .disp = dst_frame_addr.off + info.offsets[0],5774 .disp = dst_frame_addr.off + info.offsets[0],
5111 }),5775 }),
5112 Immediate.u(63),5776 tmp_reg,
5113 ),5777 );
5114 else => unreachable,
5115 }5778 }
5116 },5779 },
5117 else => {5780 else => {
...@@ -5125,7 +5788,7 @@ fn genShiftBinOpMir(...@@ -5125,7 +5788,7 @@ fn genShiftBinOpMir(
51255788
5126 try self.genSetReg(.cl, Type.u8, rhs_mcv);5789 try self.genSetReg(.cl, Type.u8, rhs_mcv);
5127 try self.asmRegisterMemory(5790 try self.asmRegisterMemory(
5128 .mov,5791 .{ ._, .mov },
5129 first_reg,5792 first_reg,
5130 Memory.sib(.qword, .{5793 Memory.sib(.qword, .{
5131 .base = .{ .frame = dst_frame_addr.index },5794 .base = .{ .frame = dst_frame_addr.index },
...@@ -5133,32 +5796,28 @@ fn genShiftBinOpMir(...@@ -5133,32 +5796,28 @@ fn genShiftBinOpMir(
5133 }),5796 }),
5134 );5797 );
5135 try self.asmRegisterMemory(5798 try self.asmRegisterMemory(
5136 .mov,5799 .{ ._, .mov },
5137 second_reg,5800 second_reg,
5138 Memory.sib(.qword, .{5801 Memory.sib(.qword, .{
5139 .base = .{ .frame = dst_frame_addr.index },5802 .base = .{ .frame = dst_frame_addr.index },
5140 .disp = dst_frame_addr.off + info.offsets[1],5803 .disp = dst_frame_addr.off + info.offsets[1],
5141 }),5804 }),
5142 );5805 );
5143 switch (tag) {5806 if (tag[0] == ._r and tag[1] == .sa) {
5144 .shl, .sal, .shr => try self.asmRegisterRegister(5807 try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, first_reg);
5145 .xor,5808 try self.asmRegisterImmediate(tag, tmp_reg, Immediate.u(63));
5146 tmp_reg.to32(),5809 } else try self.asmRegisterRegister(
5147 tmp_reg.to32(),5810 .{ ._, .xor },
5148 ),5811 tmp_reg.to32(),
5149 .sar => {5812 tmp_reg.to32(),
5150 try self.asmRegisterRegister(.mov, tmp_reg, first_reg);5813 );
5151 try self.asmRegisterImmediate(tag, tmp_reg, Immediate.u(63));
5152 },
5153 else => unreachable,
5154 }
5155 try self.asmRegisterRegisterRegister(info.double_tag, second_reg, first_reg, .cl);5814 try self.asmRegisterRegisterRegister(info.double_tag, second_reg, first_reg, .cl);
5156 try self.asmRegisterRegister(tag, first_reg, .cl);5815 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));
5158 try self.asmCmovccRegisterRegister(second_reg, first_reg, .ae);5817 try self.asmCmovccRegisterRegister(second_reg, first_reg, .ae);
5159 try self.asmCmovccRegisterRegister(first_reg, tmp_reg, .ae);5818 try self.asmCmovccRegisterRegister(first_reg, tmp_reg, .ae);
5160 try self.asmMemoryRegister(5819 try self.asmMemoryRegister(
5161 .mov,5820 .{ ._, .mov },
5162 Memory.sib(.qword, .{5821 Memory.sib(.qword, .{
5163 .base = .{ .frame = dst_frame_addr.index },5822 .base = .{ .frame = dst_frame_addr.index },
5164 .disp = dst_frame_addr.off + info.offsets[1],5823 .disp = dst_frame_addr.off + info.offsets[1],
...@@ -5166,7 +5825,7 @@ fn genShiftBinOpMir(...@@ -5166,7 +5825,7 @@ fn genShiftBinOpMir(
5166 second_reg,5825 second_reg,
5167 );5826 );
5168 try self.asmMemoryRegister(5827 try self.asmMemoryRegister(
5169 .mov,5828 .{ ._, .mov },
5170 Memory.sib(.qword, .{5829 Memory.sib(.qword, .{
5171 .base = .{ .frame = dst_frame_addr.index },5830 .base = .{ .frame = dst_frame_addr.index },
5172 .disp = dst_frame_addr.off + info.offsets[0],5831 .disp = dst_frame_addr.off + info.offsets[0],
...@@ -5191,7 +5850,7 @@ fn genShiftBinOpMir(...@@ -5191,7 +5850,7 @@ fn genShiftBinOpMir(
5191/// Asserts .rcx is free.5850/// Asserts .rcx is free.
5192fn genShiftBinOp(5851fn genShiftBinOp(
5193 self: *Self,5852 self: *Self,
5194 tag: Air.Inst.Tag,5853 air_tag: Air.Inst.Tag,
5195 maybe_inst: ?Air.Inst.Index,5854 maybe_inst: ?Air.Inst.Index,
5196 lhs_mcv: MCValue,5855 lhs_mcv: MCValue,
5197 rhs_mcv: MCValue,5856 rhs_mcv: MCValue,
...@@ -5236,14 +5895,14 @@ fn genShiftBinOp(...@@ -5236,14 +5895,14 @@ fn genShiftBinOp(
5236 };5895 };
52375896
5238 const signedness = lhs_ty.intInfo(self.target.*).signedness;5897 const signedness = lhs_ty.intInfo(self.target.*).signedness;
5239 try self.genShiftBinOpMir(switch (tag) {5898 try self.genShiftBinOpMir(switch (air_tag) {
5240 .shl, .shl_exact => switch (signedness) {5899 .shl, .shl_exact => switch (signedness) {
5241 .signed => .sal,5900 .signed => .{ ._l, .sa },
5242 .unsigned => .shl,5901 .unsigned => .{ ._l, .sh },
5243 },5902 },
5244 .shr, .shr_exact => switch (signedness) {5903 .shr, .shr_exact => switch (signedness) {
5245 .signed => .sar,5904 .signed => .{ ._r, .sa },
5246 .unsigned => .shr,5905 .unsigned => .{ ._r, .sh },
5247 },5906 },
5248 else => unreachable,5907 else => unreachable,
5249 }, lhs_ty, dst_mcv, rhs_mcv);5908 }, lhs_ty, dst_mcv, rhs_mcv);
...@@ -5303,20 +5962,18 @@ fn genMulDivBinOp(...@@ -5303,20 +5962,18 @@ fn genMulDivBinOp(
5303 try self.register_manager.getReg(.rax, track_inst_rax);5962 try self.register_manager.getReg(.rax, track_inst_rax);
5304 try self.register_manager.getReg(.rdx, track_inst_rdx);5963 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) {
5307 .signed => switch (tag) {5966 .signed => switch (tag) {
5308 .mul, .mulwrap => .imul,5967 .mul, .mulwrap => .{ .i_, .mul },
5309 .div_trunc, .div_exact, .rem => .idiv,5968 .div_trunc, .div_exact, .rem => .{ .i_, .div },
5310 else => unreachable,5969 else => unreachable,
5311 },5970 },
5312 .unsigned => switch (tag) {5971 .unsigned => switch (tag) {
5313 .mul, .mulwrap => .mul,5972 .mul, .mulwrap => .{ ._, .mul },
5314 .div_trunc, .div_exact, .rem => .div,5973 .div_trunc, .div_exact, .rem => .{ ._, .div },
5315 else => unreachable,5974 else => unreachable,
5316 },5975 },
5317 };5976 }, ty, lhs, rhs);
5318
5319 try self.genIntMulDivOpMir(mir_tag, ty, lhs, rhs);
53205977
5321 if (dst_abi_size <= 8) return .{ .register = registerAlias(switch (tag) {5978 if (dst_abi_size <= 8) return .{ .register = registerAlias(switch (tag) {
5322 .mul, .mulwrap, .div_trunc, .div_exact => .rax,5979 .mul, .mulwrap, .div_trunc, .div_exact => .rax,
...@@ -5326,7 +5983,7 @@ fn genMulDivBinOp(...@@ -5326,7 +5983,7 @@ fn genMulDivBinOp(
53265983
5327 const dst_mcv = try self.allocRegOrMemAdvanced(dst_ty, maybe_inst, false);5984 const dst_mcv = try self.allocRegOrMemAdvanced(dst_ty, maybe_inst, false);
5328 try self.asmMemoryRegister(5985 try self.asmMemoryRegister(
5329 .mov,5986 .{ ._, .mov },
5330 Memory.sib(.qword, .{5987 Memory.sib(.qword, .{
5331 .base = .{ .frame = dst_mcv.load_frame.index },5988 .base = .{ .frame = dst_mcv.load_frame.index },
5332 .disp = dst_mcv.load_frame.off,5989 .disp = dst_mcv.load_frame.off,
...@@ -5334,7 +5991,7 @@ fn genMulDivBinOp(...@@ -5334,7 +5991,7 @@ fn genMulDivBinOp(
5334 .rax,5991 .rax,
5335 );5992 );
5336 try self.asmMemoryRegister(5993 try self.asmMemoryRegister(
5337 .mov,5994 .{ ._, .mov },
5338 Memory.sib(.qword, .{5995 Memory.sib(.qword, .{
5339 .base = .{ .frame = dst_mcv.load_frame.index },5996 .base = .{ .frame = dst_mcv.load_frame.index },
5340 .disp = dst_mcv.load_frame.off + 8,5997 .disp = dst_mcv.load_frame.off + 8,
...@@ -5375,12 +6032,12 @@ fn genMulDivBinOp(...@@ -5375,12 +6032,12 @@ fn genMulDivBinOp(
5375 try self.copyToRegisterWithInstTracking(inst, ty, lhs)6032 try self.copyToRegisterWithInstTracking(inst, ty, lhs)
5376 else6033 else
5377 .{ .register = try self.copyToTmpRegister(ty, lhs) };6034 .{ .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
5380 return result;6037 return result;
5381 },6038 },
5382 .unsigned => {6039 .unsigned => {
5383 try self.genIntMulDivOpMir(.div, ty, lhs, rhs);6040 try self.genIntMulDivOpMir(.{ ._, .div }, ty, lhs, rhs);
5384 return .{ .register = registerAlias(.rdx, abi_size) };6041 return .{ .register = registerAlias(.rdx, abi_size) };
5385 },6042 },
5386 }6043 }
...@@ -5422,7 +6079,7 @@ fn genMulDivBinOp(...@@ -5422,7 +6079,7 @@ fn genMulDivBinOp(
5422 switch (signedness) {6079 switch (signedness) {
5423 .signed => return try self.genInlineIntDivFloor(ty, lhs, actual_rhs),6080 .signed => return try self.genInlineIntDivFloor(ty, lhs, actual_rhs),
5424 .unsigned => {6081 .unsigned => {
5425 try self.genIntMulDivOpMir(.div, ty, lhs, actual_rhs);6082 try self.genIntMulDivOpMir(.{ ._, .div }, ty, lhs, actual_rhs);
5426 return .{ .register = registerAlias(.rax, abi_size) };6083 return .{ .register = registerAlias(.rax, abi_size) };
5427 },6084 },
5428 }6085 }
...@@ -5432,25 +6089,22 @@ fn genMulDivBinOp(...@@ -5432,25 +6089,22 @@ fn genMulDivBinOp(
5432 }6089 }
5433}6090}
54346091
5435/// Result is always a register.
5436fn genBinOp(6092fn genBinOp(
5437 self: *Self,6093 self: *Self,
5438 maybe_inst: ?Air.Inst.Index,6094 maybe_inst: ?Air.Inst.Index,
5439 tag: Air.Inst.Tag,6095 air_tag: Air.Inst.Tag,
5440 lhs_air: Air.Inst.Ref,6096 lhs_air: Air.Inst.Ref,
5441 rhs_air: Air.Inst.Ref,6097 rhs_air: Air.Inst.Ref,
5442) !MCValue {6098) !MCValue {
5443 const lhs = try self.resolveInst(lhs_air);6099 const lhs_mcv = try self.resolveInst(lhs_air);
5444 const rhs = try self.resolveInst(rhs_air);6100 const rhs_mcv = try self.resolveInst(rhs_air);
5445 const lhs_ty = self.air.typeOf(lhs_air);6101 const lhs_ty = self.air.typeOf(lhs_air);
5446 const rhs_ty = self.air.typeOf(rhs_air);6102 const rhs_ty = self.air.typeOf(rhs_air);
5447 if (lhs_ty.zigTypeTag() == .Vector) {6103 const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
5448 return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)});
5449 }
54506104
5451 switch (lhs) {6105 switch (lhs_mcv) {
5452 .immediate => |imm| switch (imm) {6106 .immediate => |imm| switch (imm) {
5453 0 => switch (tag) {6107 0 => switch (air_tag) {
5454 .sub, .subwrap => return self.genUnOp(maybe_inst, .neg, rhs_air),6108 .sub, .subwrap => return self.genUnOp(maybe_inst, .neg, rhs_air),
5455 else => {},6109 else => {},
5456 },6110 },
...@@ -5459,9 +6113,10 @@ fn genBinOp(...@@ -5459,9 +6113,10 @@ fn genBinOp(
5459 else => {},6113 else => {},
5460 }6114 }
54616115
5462 const is_commutative = switch (tag) {6116 const is_commutative = switch (air_tag) {
5463 .add,6117 .add,
5464 .addwrap,6118 .addwrap,
6119 .mul,
5465 .bool_or,6120 .bool_or,
5466 .bit_or,6121 .bit_or,
5467 .bool_and,6122 .bool_and,
...@@ -5473,48 +6128,42 @@ fn genBinOp(...@@ -5473,48 +6128,42 @@ fn genBinOp(
54736128
5474 else => false,6129 else => false,
5475 };6130 };
5476 const dst_mem_ok = switch (tag) {6131 const vec_op = switch (lhs_ty.zigTypeTag()) {
5477 .add,6132 else => false,
5478 .addwrap,6133 .Float, .Vector => true,
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,
5489 };6134 };
54906135
5491 const lhs_lock: ?RegisterLock = switch (lhs) {6136 const lhs_lock: ?RegisterLock = switch (lhs_mcv) {
5492 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),6137 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
5493 else => null,6138 else => null,
5494 };6139 };
5495 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);6140 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) {
5498 .register => |reg| self.register_manager.lockReg(reg),6143 .register => |reg| self.register_manager.lockReg(reg),
5499 else => null,6144 else => null,
5500 };6145 };
5501 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);6146 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;
5504 const dst_mcv: MCValue = dst: {6150 const dst_mcv: MCValue = dst: {
5505 if (maybe_inst) |inst| {6151 if (maybe_inst) |inst| {
5506 if ((dst_mem_ok or lhs.isRegister()) and self.reuseOperand(inst, lhs_air, 0, lhs)) {6152 if ((!vec_op or lhs_mcv.isRegister()) and self.reuseOperand(inst, lhs_air, 0, lhs_mcv)) {
5507 break :dst lhs;6153 break :dst lhs_mcv;
5508 }6154 }
5509 if (is_commutative and (dst_mem_ok or rhs.isRegister()) and6155 if (is_commutative and (!vec_op or rhs_mcv.isRegister()) and
5510 self.reuseOperand(inst, rhs_air, 1, rhs))6156 self.reuseOperand(inst, rhs_air, 1, rhs_mcv))
5511 {6157 {
5512 flipped = true;6158 flipped = true;
5513 break :dst rhs;6159 break :dst rhs_mcv;
5514 }6160 }
5515 }6161 }
5516 const dst_mcv = try self.allocRegOrMemAdvanced(lhs_ty, maybe_inst, true);6162 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);
5518 break :dst dst_mcv;6167 break :dst dst_mcv;
5519 };6168 };
5520 const dst_lock: ?RegisterLock = switch (dst_mcv) {6169 const dst_lock: ?RegisterLock = switch (dst_mcv) {
...@@ -5523,160 +6172,52 @@ fn genBinOp(...@@ -5523,160 +6172,52 @@ fn genBinOp(
5523 };6172 };
5524 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);6173 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
55256174
5526 const src_mcv = if (flipped) lhs else rhs;6175 const src_mcv = if (flipped) lhs_mcv else rhs_mcv;
5527 switch (tag) {6176 if (!vec_op) {
5528 .add,6177 switch (air_tag) {
5529 .addwrap,6178 .add,
5530 => try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) {6179 .addwrap,
5531 else => .add,6180 => try self.genBinOpMir(.{ ._, .add }, lhs_ty, dst_mcv, src_mcv),
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),
55966181
5597 .div_float,6182 .sub,
5598 .div_exact,6183 .subwrap,
5599 .div_trunc,6184 => try self.genBinOpMir(.{ ._, .sub }, lhs_ty, dst_mcv, src_mcv),
5600 .div_floor,6185
5601 => {6186 .ptr_add,
5602 try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) {6187 .ptr_sub,
5603 else => return self.fail("TODO implement genBinOp for {s} {}", .{6188 => {
5604 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),6189 const tmp_reg = try self.copyToTmpRegister(rhs_ty, src_mcv);
5605 }),6190 const tmp_mcv = MCValue{ .register = tmp_reg };
5606 .Float => switch (lhs_ty.floatBits(self.target.*)) {6191 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
5607 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse))6192 defer self.register_manager.unlockReg(tmp_lock);
5608 .divss6193
5609 else6194 const elem_size = lhs_ty.elemType2().abiSize(self.target.*);
5610 return self.fail("TODO implement genBinOp for {s} {} without sse", .{6195 try self.genIntMulComplexOpMir(rhs_ty, tmp_mcv, .{ .immediate = elem_size });
5611 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),6196 try self.genBinOpMir(
5612 }),6197 switch (air_tag) {
5613 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2))6198 .ptr_add => .{ ._, .add },
5614 .divsd6199 .ptr_sub => .{ ._, .sub },
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,
5640 else => unreachable,6200 else => unreachable,
5641 }));6201 },
5642 } else return self.fail("TODO implement genBinOp for {s} {} without sse4_1", .{6202 lhs_ty,
5643 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),6203 dst_mcv,
5644 }),6204 tmp_mcv,
5645 else => unreachable,6205 );
5646 }6206 },
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 },
56656207
5666 .bool_or,6208 .bool_or,
5667 .bit_or,6209 .bit_or,
5668 => try self.genBinOpMir(.@"or", lhs_ty, dst_mcv, src_mcv),6210 => try self.genBinOpMir(.{ ._, .@"or" }, lhs_ty, dst_mcv, src_mcv),
56696211
5670 .bool_and,6212 .bool_and,
5671 .bit_and,6213 .bit_and,
5672 => try self.genBinOpMir(.@"and", lhs_ty, dst_mcv, src_mcv),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,6218 .min,
5677 .max,6219 .max,
5678 => switch (lhs_ty.zigTypeTag()) {6220 => {
5679 .Int => {
5680 const mat_src_mcv: MCValue = if (switch (src_mcv) {6221 const mat_src_mcv: MCValue = if (switch (src_mcv) {
5681 .immediate,6222 .immediate,
5682 .eflags,6223 .eflags,
...@@ -5698,16 +6239,16 @@ fn genBinOp(...@@ -5698,16 +6239,16 @@ fn genBinOp(
5698 };6239 };
5699 defer if (mat_mcv_lock) |lock| self.register_manager.unlockReg(lock);6240 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
5703 const int_info = lhs_ty.intInfo(self.target.*);6244 const int_info = lhs_ty.intInfo(self.target.*);
5704 const cc: Condition = switch (int_info.signedness) {6245 const cc: Condition = switch (int_info.signedness) {
5705 .unsigned => switch (tag) {6246 .unsigned => switch (air_tag) {
5706 .min => .a,6247 .min => .a,
5707 .max => .b,6248 .max => .b,
5708 else => unreachable,6249 else => unreachable,
5709 },6250 },
5710 .signed => switch (tag) {6251 .signed => switch (air_tag) {
5711 .min => .g,6252 .min => .g,
5712 .max => .l,6253 .max => .l,
5713 else => unreachable,6254 else => unreachable,
...@@ -5766,32 +6307,404 @@ fn genBinOp(...@@ -5766,32 +6307,404 @@ fn genBinOp(
5766 }6307 }
5767 try self.genCopy(lhs_ty, dst_mcv, .{ .register = tmp_reg });6308 try self.genCopy(lhs_ty, dst_mcv, .{ .register = tmp_reg });
5768 },6309 },
5769 .Float => try self.genBinOpMir(switch (lhs_ty.floatBits(self.target.*)) {6310
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),
5784 else => return self.fail("TODO implement genBinOp for {s} {}", .{6311 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.?),
5786 }),6313 }),
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
5789 else => unreachable,6696 else => unreachable,
5790 }6697 }
5791 return dst_mcv;6698 return dst_mcv;
5792}6699}
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 {
5795 const abi_size = @intCast(u32, ty.abiSize(self.target.*));6708 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
5796 switch (dst_mcv) {6709 switch (dst_mcv) {
5797 .none,6710 .none,
...@@ -5818,20 +6731,11 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s...@@ -5818,20 +6731,11 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
5818 .register_overflow,6731 .register_overflow,
5819 .reserved_frame,6732 .reserved_frame,
5820 => unreachable,6733 => unreachable,
5821 .register => |src_reg| switch (ty.zigTypeTag()) {6734 .register => |src_reg| try self.asmRegisterRegister(
5822 .Float => {6735 mir_tag,
5823 if (!Target.x86.featureSetHas(self.target.cpu.features, .sse))6736 dst_alias,
5824 return self.fail("TODO genBinOpMir for {s} {} without sse", .{6737 registerAlias(src_reg, abi_size),
5825 @tagName(mir_tag), ty.fmt(self.bin_file.options.module.?),6738 ),
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 },
5835 .immediate => |imm| switch (self.regBitSize(ty)) {6739 .immediate => |imm| switch (self.regBitSize(ty)) {
5836 8 => try self.asmRegisterImmediate(6740 8 => try self.asmRegisterImmediate(
5837 mir_tag,6741 mir_tag,
...@@ -6005,14 +6909,14 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s...@@ -6005,14 +6909,14 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
6005 };6909 };
6006 var off: i32 = 0;6910 var off: i32 = 0;
6007 while (off < abi_size) : (off += 8) {6911 while (off < abi_size) : (off += 8) {
6008 const mir_limb_tag = switch (off) {6912 const mir_limb_tag: Mir.Inst.FixedTag = switch (off) {
6009 0 => mir_tag,6913 0 => mir_tag,
6010 else => switch (mir_tag) {6914 else => switch (mir_tag[1]) {
6011 .add => .adc,6915 .add => .{ ._, .adc },
6012 .sub, .cmp => .sbb,6916 .sub, .cmp => .{ ._, .sbb },
6013 .@"or", .@"and", .xor => mir_tag,6917 .@"or", .@"and", .xor => mir_tag,
6014 else => return self.fail("TODO genBinOpMir implement large ABI for {s}", .{6918 else => return self.fail("TODO genBinOpMir implement large ABI for {s}", .{
6015 @tagName(mir_tag),6919 @tagName(mir_tag[1]),
6016 }),6920 }),
6017 },6921 },
6018 };6922 };
...@@ -6184,14 +7088,14 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -6184,14 +7088,14 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
6184 .reserved_frame,7088 .reserved_frame,
6185 => unreachable,7089 => unreachable,
6186 .register => |src_reg| try self.asmRegisterRegister(7090 .register => |src_reg| try self.asmRegisterRegister(
6187 .imul,7091 .{ .i_, .mul },
6188 dst_alias,7092 dst_alias,
6189 registerAlias(src_reg, abi_size),7093 registerAlias(src_reg, abi_size),
6190 ),7094 ),
6191 .immediate => |imm| {7095 .immediate => |imm| {
6192 if (math.cast(i32, imm)) |small| {7096 if (math.cast(i32, imm)) |small| {
6193 try self.asmRegisterRegisterImmediate(7097 try self.asmRegisterRegisterImmediate(
6194 .imul,7098 .{ .i_, .mul },
6195 dst_alias,7099 dst_alias,
6196 dst_alias,7100 dst_alias,
6197 Immediate.s(small),7101 Immediate.s(small),
...@@ -6211,19 +7115,19 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -6211,19 +7115,19 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
6211 .lea_tlv,7115 .lea_tlv,
6212 .lea_frame,7116 .lea_frame,
6213 => try self.asmRegisterRegister(7117 => try self.asmRegisterRegister(
6214 .imul,7118 .{ .i_, .mul },
6215 dst_alias,7119 dst_alias,
6216 registerAlias(try self.copyToTmpRegister(dst_ty, src_mcv), abi_size),7120 registerAlias(try self.copyToTmpRegister(dst_ty, src_mcv), abi_size),
6217 ),7121 ),
6218 .memory, .indirect, .load_frame => try self.asmRegisterMemory(7122 .memory, .indirect, .load_frame => try self.asmRegisterMemory(
6219 .imul,7123 .{ .i_, .mul },
6220 dst_alias,7124 dst_alias,
6221 Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (src_mcv) {7125 Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (src_mcv) {
6222 .memory => |addr| .{7126 .memory => |addr| .{
6223 .base = .{ .reg = .ds },7127 .base = .{ .reg = .ds },
6224 .disp = math.cast(i32, @bitCast(i64, addr)) orelse7128 .disp = math.cast(i32, @bitCast(i64, addr)) orelse
6225 return self.asmRegisterRegister(7129 return self.asmRegisterRegister(
6226 .imul,7130 .{ .i_, .mul },
6227 dst_alias,7131 dst_alias,
6228 registerAlias(try self.copyToTmpRegister(dst_ty, src_mcv), abi_size),7132 registerAlias(try self.copyToTmpRegister(dst_ty, src_mcv), abi_size),
6229 ),7133 ),
...@@ -6348,12 +7252,12 @@ fn genVarDbgInfo(...@@ -6348,12 +7252,12 @@ fn genVarDbgInfo(
6348}7252}
63497253
6350fn airTrap(self: *Self) !void {7254fn airTrap(self: *Self) !void {
6351 try self.asmOpOnly(.ud2);7255 try self.asmOpOnly(.{ ._, .ud2 });
6352 return self.finishAirBookkeeping();7256 return self.finishAirBookkeeping();
6353}7257}
63547258
6355fn airBreakpoint(self: *Self) !void {7259fn airBreakpoint(self: *Self) !void {
6356 try self.asmOpOnly(.int3);7260 try self.asmOpOnly(.{ ._, .int3 });
6357 return self.finishAirBookkeeping();7261 return self.finishAirBookkeeping();
6358}7262}
63597263
...@@ -6374,7 +7278,7 @@ fn airFence(self: *Self, inst: Air.Inst.Index) !void {...@@ -6374,7 +7278,7 @@ fn airFence(self: *Self, inst: Air.Inst.Index) !void {
6374 switch (order) {7278 switch (order) {
6375 .Unordered, .Monotonic => unreachable,7279 .Unordered, .Monotonic => unreachable,
6376 .Acquire, .Release, .AcqRel => {},7280 .Acquire, .Release, .AcqRel => {},
6377 .SeqCst => try self.asmOpOnly(.mfence),7281 .SeqCst => try self.asmOpOnly(.{ ._, .mfence }),
6378 }7282 }
6379 return self.finishAirBookkeeping();7283 return self.finishAirBookkeeping();
6380}7284}
...@@ -6468,7 +7372,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -6468,7 +7372,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
6468 const atom = elf_file.getAtom(atom_index);7372 const atom = elf_file.getAtom(atom_index);
6469 _ = try atom.getOrCreateOffsetTableEntry(elf_file);7373 _ = try atom.getOrCreateOffsetTableEntry(elf_file);
6470 const got_addr = atom.getOffsetTableAddress(elf_file);7374 const got_addr = atom.getOffsetTableAddress(elf_file);
6471 try self.asmMemory(.call, Memory.sib(.qword, .{7375 try self.asmMemory(.{ ._, .call }, Memory.sib(.qword, .{
6472 .base = .{ .reg = .ds },7376 .base = .{ .reg = .ds },
6473 .disp = @intCast(i32, got_addr),7377 .disp = @intCast(i32, got_addr),
6474 }));7378 }));
...@@ -6476,12 +7380,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -6476,12 +7380,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
6476 const atom = try coff_file.getOrCreateAtomForDecl(func.owner_decl);7380 const atom = try coff_file.getOrCreateAtomForDecl(func.owner_decl);
6477 const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;7381 const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;
6478 try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });7382 try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });
6479 try self.asmRegister(.call, .rax);7383 try self.asmRegister(.{ ._, .call }, .rax);
6480 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {7384 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
6481 const atom = try macho_file.getOrCreateAtomForDecl(func.owner_decl);7385 const atom = try macho_file.getOrCreateAtomForDecl(func.owner_decl);
6482 const sym_index = macho_file.getAtom(atom).getSymbolIndex().?;7386 const sym_index = macho_file.getAtom(atom).getSymbolIndex().?;
6483 try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });7387 try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });
6484 try self.asmRegister(.call, .rax);7388 try self.asmRegister(.{ ._, .call }, .rax);
6485 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {7389 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
6486 const decl_block_index = try p9.seeDecl(func.owner_decl);7390 const decl_block_index = try p9.seeDecl(func.owner_decl);
6487 const decl_block = p9.getDeclBlock(decl_block_index);7391 const decl_block = p9.getDeclBlock(decl_block_index);
...@@ -6490,7 +7394,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -6490,7 +7394,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
6490 const got_addr = p9.bases.data;7394 const got_addr = p9.bases.data;
6491 const got_index = decl_block.got_index.?;7395 const got_index = decl_block.got_index.?;
6492 const fn_got_addr = got_addr + got_index * ptr_bytes;7396 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, .{
6494 .base = .{ .reg = .ds },7398 .base = .{ .reg = .ds },
6495 .disp = @intCast(i32, fn_got_addr),7399 .disp = @intCast(i32, fn_got_addr),
6496 }));7400 }));
...@@ -6503,22 +7407,24 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -6503,22 +7407,24 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
6503 const atom_index = try self.owner.getSymbolIndex(self);7407 const atom_index = try self.owner.getSymbolIndex(self);
6504 const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name);7408 const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name);
6505 _ = try self.addInst(.{7409 _ = try self.addInst(.{
6506 .tag = .mov_linker,7410 .tag = .mov,
6507 .ops = .import_reloc,7411 .ops = .import_reloc,
6508 .data = .{ .payload = try self.addExtra(Mir.LeaRegisterReloc{7412 .data = .{ .rx = .{
6509 .reg = @enumToInt(Register.rax),7413 .r1 = .rax,
6510 .atom_index = atom_index,7414 .payload = try self.addExtra(Mir.Reloc{
6511 .sym_index = sym_index,7415 .atom_index = atom_index,
6512 }) },7416 .sym_index = sym_index,
7417 }),
7418 } },
6513 });7419 });
6514 try self.asmRegister(.call, .rax);7420 try self.asmRegister(.{ ._, .call }, .rax);
6515 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {7421 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
6516 const atom_index = try self.owner.getSymbolIndex(self);7422 const atom_index = try self.owner.getSymbolIndex(self);
6517 const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name);7423 const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name);
6518 _ = try self.addInst(.{7424 _ = try self.addInst(.{
6519 .tag = .call_extern,7425 .tag = .call,
6520 .ops = undefined,7426 .ops = .extern_fn_reloc,
6521 .data = .{ .relocation = .{7427 .data = .{ .reloc = .{
6522 .atom_index = atom_index,7428 .atom_index = atom_index,
6523 .sym_index = sym_index,7429 .sym_index = sym_index,
6524 } },7430 } },
...@@ -6533,7 +7439,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -6533,7 +7439,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
6533 assert(ty.zigTypeTag() == .Pointer);7439 assert(ty.zigTypeTag() == .Pointer);
6534 const mcv = try self.resolveInst(callee);7440 const mcv = try self.resolveInst(callee);
6535 try self.genSetReg(.rax, Type.usize, mcv);7441 try self.genSetReg(.rax, Type.usize, mcv);
6536 try self.asmRegister(.call, .rax);7442 try self.asmRegister(.{ ._, .call }, .rax);
6537 }7443 }
65387444
6539 var bt = self.liveness.iterateBigTomb(inst);7445 var bt = self.liveness.iterateBigTomb(inst);
...@@ -6588,8 +7494,6 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -6588,8 +7494,6 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
6588fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {7494fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
6589 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7495 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
6590 const ty = self.air.typeOf(bin_op.lhs);7496 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
6594 try self.spillEflagsIfOccupied();7498 try self.spillEflagsIfOccupied();
6595 self.eflags_inst = inst;7499 self.eflags_inst = inst;
...@@ -6608,52 +7512,103 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -6608,52 +7512,103 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
6608 };7512 };
6609 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);7513 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
66107514
6611 const dst_mem_ok = !ty.isRuntimeFloat();7515 const result = MCValue{
6612 var flipped = false;7516 .eflags = switch (ty.zigTypeTag()) {
6613 const dst_mcv: MCValue = if (can_reuse and !lhs_mcv.isImmediate() and7517 else => result: {
6614 (dst_mem_ok or lhs_mcv.isRegister()) and self.liveness.operandDies(inst, 0))7518 var flipped = false;
6615 lhs_mcv7519 const dst_mcv: MCValue = if (lhs_mcv.isRegister() or lhs_mcv.isMemory())
6616 else if (can_reuse and !rhs_mcv.isImmediate() and7520 lhs_mcv
6617 (dst_mem_ok or rhs_mcv.isRegister()) and self.liveness.operandDies(inst, 1))7521 else if (rhs_mcv.isRegister() or rhs_mcv.isMemory()) dst: {
6618 dst: {7522 flipped = true;
6619 flipped = true;7523 break :dst rhs_mcv;
6620 break :dst rhs_mcv;7524 } else .{ .register = try self.copyToTmpRegister(ty, lhs_mcv) };
6621 } else if (dst_mem_ok) dst: {7525 const dst_lock = switch (dst_mcv) {
6622 const dst_mcv = try self.allocTempRegOrMem(ty, true);7526 .register => |reg| self.register_manager.lockReg(reg),
6623 try self.genCopy(ty, dst_mcv, lhs_mcv);7527 else => null,
6624 break :dst dst_mcv;7528 };
6625 } else .{ .register = try self.copyToTmpRegister(ty, lhs_mcv) };7529 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
6626 const dst_lock = switch (dst_mcv) {7530 const src_mcv = if (flipped) lhs_mcv else rhs_mcv;
6627 .register => |reg| self.register_manager.lockReg(reg),
6628 else => null,
6629 };
6630 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
66317531
6632 const src_mcv = if (flipped) lhs_mcv else rhs_mcv;7532 try self.genBinOpMir(.{ ._, .cmp }, ty, dst_mcv, src_mcv);
6633 try self.genBinOpMir(switch (ty.zigTypeTag()) {7533 break :result Condition.fromCompareOperator(
6634 else => .cmp,7534 if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned,
6635 .Float => switch (ty.floatBits(self.target.*)) {7535 if (flipped) op.reverse() else op,
6636 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse))7536 );
6637 .ucomiss7537 },
6638 else7538 .Float => result: {
6639 return self.fail("TODO implement airCmp for {} without sse", .{7539 const flipped = switch (op) {
6640 ty.fmt(self.bin_file.options.module.?),7540 .lt, .lte => true,
6641 }),7541 .eq, .gte, .gt, .neq => false,
6642 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2))7542 };
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);
66537543
6654 const signedness = if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned;7544 const dst_mcv = if (flipped) rhs_mcv else lhs_mcv;
6655 const result = MCValue{7545 const dst_reg = if (dst_mcv.isRegister())
6656 .eflags = Condition.fromCompareOperator(signedness, if (flipped) op.reverse() else op),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 },
6657 };7612 };
6658 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });7613 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
6659}7614}
...@@ -6683,7 +7638,7 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {...@@ -6683,7 +7638,7 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {
6683 else => try self.copyToTmpRegister(op_ty, op_mcv),7638 else => try self.copyToTmpRegister(op_ty, op_mcv),
6684 };7639 };
6685 try self.asmRegisterMemory(7640 try self.asmRegisterMemory(
6686 .cmp,7641 .{ ._, .cmp },
6687 registerAlias(dst_reg, op_abi_size),7642 registerAlias(dst_reg, op_abi_size),
6688 Memory.sib(Memory.PtrSize.fromSize(op_abi_size), .{ .base = .{ .reg = addr_reg } }),7643 Memory.sib(Memory.PtrSize.fromSize(op_abi_size), .{ .base = .{ .reg = addr_reg } }),
6689 );7644 );
...@@ -6757,8 +7712,8 @@ fn genTry(...@@ -6757,8 +7712,8 @@ fn genTry(
6757fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {7712fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
6758 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;7713 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
6759 _ = try self.addInst(.{7714 _ = try self.addInst(.{
6760 .tag = .dbg_line,7715 .tag = .pseudo,
6761 .ops = undefined,7716 .ops = .pseudo_dbg_line_line_column,
6762 .data = .{ .line_column = .{7717 .data = .{ .line_column = .{
6763 .line = dbg_stmt.line,7718 .line = dbg_stmt.line,
6764 .column = dbg_stmt.column,7719 .column = dbg_stmt.column,
...@@ -6803,7 +7758,7 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {...@@ -6803,7 +7758,7 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {
6803 },7758 },
6804 .register => |reg| {7759 .register => |reg| {
6805 try self.spillEflagsIfOccupied();7760 try self.spillEflagsIfOccupied();
6806 try self.asmRegisterImmediate(.@"test", reg, Immediate.u(1));7761 try self.asmRegisterImmediate(.{ ._, .@"test" }, reg, Immediate.u(1));
6807 return self.asmJccReloc(undefined, .e);7762 return self.asmJccReloc(undefined, .e);
6808 },7763 },
6809 .immediate,7764 .immediate,
...@@ -6906,13 +7861,13 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC...@@ -6906,13 +7861,13 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
6906 const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*));7861 const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*));
6907 const alias_reg = registerAlias(opt_reg, some_abi_size);7862 const alias_reg = registerAlias(opt_reg, some_abi_size);
6908 assert(some_abi_size * 8 == alias_reg.bitSize());7863 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);
6910 return .{ .eflags = .z };7865 return .{ .eflags = .z };
6911 }7866 }
6912 assert(some_info.ty.tag() == .bool);7867 assert(some_info.ty.tag() == .bool);
6913 const opt_abi_size = @intCast(u32, opt_ty.abiSize(self.target.*));7868 const opt_abi_size = @intCast(u32, opt_ty.abiSize(self.target.*));
6914 try self.asmRegisterImmediate(7869 try self.asmRegisterImmediate(
6915 .bt,7870 .{ ._, .bt },
6916 registerAlias(opt_reg, opt_abi_size),7871 registerAlias(opt_reg, opt_abi_size),
6917 Immediate.u(@intCast(u6, some_info.off * 8)),7872 Immediate.u(@intCast(u6, some_info.off * 8)),
6918 );7873 );
...@@ -6931,7 +7886,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC...@@ -6931,7 +7886,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
6931 try self.genSetReg(addr_reg, Type.usize, opt_mcv.address());7886 try self.genSetReg(addr_reg, Type.usize, opt_mcv.address());
6932 const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*));7887 const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*));
6933 try self.asmMemoryImmediate(7888 try self.asmMemoryImmediate(
6934 .cmp,7889 .{ ._, .cmp },
6935 Memory.sib(Memory.PtrSize.fromSize(some_abi_size), .{7890 Memory.sib(Memory.PtrSize.fromSize(some_abi_size), .{
6936 .base = .{ .reg = addr_reg },7891 .base = .{ .reg = addr_reg },
6937 .disp = some_info.off,7892 .disp = some_info.off,
...@@ -6944,7 +7899,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC...@@ -6944,7 +7899,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
6944 .indirect, .load_frame => {7899 .indirect, .load_frame => {
6945 const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*));7900 const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*));
6946 try self.asmMemoryImmediate(7901 try self.asmMemoryImmediate(
6947 .cmp,7902 .{ ._, .cmp },
6948 Memory.sib(Memory.PtrSize.fromSize(some_abi_size), switch (opt_mcv) {7903 Memory.sib(Memory.PtrSize.fromSize(some_abi_size), switch (opt_mcv) {
6949 .indirect => |reg_off| .{7904 .indirect => |reg_off| .{
6950 .base = .{ .reg = reg_off.reg },7905 .base = .{ .reg = reg_off.reg },
...@@ -6986,7 +7941,7 @@ fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue)...@@ -6986,7 +7941,7 @@ fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue)
69867941
6987 const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*));7942 const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*));
6988 try self.asmMemoryImmediate(7943 try self.asmMemoryImmediate(
6989 .cmp,7944 .{ ._, .cmp },
6990 Memory.sib(Memory.PtrSize.fromSize(some_abi_size), .{7945 Memory.sib(Memory.PtrSize.fromSize(some_abi_size), .{
6991 .base = .{ .reg = ptr_reg },7946 .base = .{ .reg = ptr_reg },
6992 .disp = some_info.off,7947 .disp = some_info.off,
...@@ -7017,14 +7972,24 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) !...@@ -7017,14 +7972,24 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) !
7017 const tmp_reg = try self.copyToTmpRegister(ty, operand);7972 const tmp_reg = try self.copyToTmpRegister(ty, operand);
7018 if (err_off > 0) {7973 if (err_off > 0) {
7019 const shift = @intCast(u6, err_off * 8);7974 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 );
7021 } else {7981 } else {
7022 try self.truncateRegister(Type.anyerror, tmp_reg);7982 try self.truncateRegister(Type.anyerror, tmp_reg);
7023 }7983 }
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 );
7025 },7990 },
7026 .load_frame => |frame_addr| try self.genBinOpMir(7991 .load_frame => |frame_addr| try self.genBinOpMir(
7027 .cmp,7992 .{ ._, .cmp },
7028 Type.anyerror,7993 Type.anyerror,
7029 .{ .load_frame = .{7994 .{ .load_frame = .{
7030 .index = frame_addr.index,7995 .index = frame_addr.index,
...@@ -7249,7 +8214,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -7249,7 +8214,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
7249 try self.spillEflagsIfOccupied();8214 try self.spillEflagsIfOccupied();
7250 for (items, relocs, 0..) |item, *reloc, i| {8215 for (items, relocs, 0..) |item, *reloc, i| {
7251 const item_mcv = try self.resolveInst(item);8216 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);
7253 reloc.* = try self.asmJccReloc(undefined, if (i < relocs.len - 1) .e else .ne);8218 reloc.* = try self.asmJccReloc(undefined, if (i < relocs.len - 1) .e else .ne);
7254 }8219 }
72558220
...@@ -7289,14 +8254,14 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -7289,14 +8254,14 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
7289fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {8254fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {
7290 const next_inst = @intCast(u32, self.mir_instructions.len);8255 const next_inst = @intCast(u32, self.mir_instructions.len);
7291 switch (self.mir_instructions.items(.tag)[reloc]) {8256 switch (self.mir_instructions.items(.tag)[reloc]) {
7292 .jcc => {8257 .j, .jmp => {},
7293 self.mir_instructions.items(.data)[reloc].inst_cc.inst = next_inst;8258 .pseudo => switch (self.mir_instructions.items(.ops)[reloc]) {
7294 },8259 .pseudo_j_z_and_np_inst, .pseudo_j_nz_or_p_inst => {},
7295 .jmp_reloc => {8260 else => unreachable,
7296 self.mir_instructions.items(.data)[reloc].inst = next_inst;
7297 },8261 },
7298 else => unreachable,8262 else => unreachable,
7299 }8263 }
8264 self.mir_instructions.items(.data)[reloc].inst.inst = next_inst;
7300}8265}
73018266
7302fn airBr(self: *Self, inst: Air.Inst.Index) !void {8267fn airBr(self: *Self, inst: Air.Inst.Index) !void {
...@@ -7460,7 +8425,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -7460,7 +8425,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
7460 .qword8425 .qword
7461 else8426 else
7462 null;8427 null;
7463 const mnem = mnem: {8428 const mnem_tag = Mir.Inst.FixedTag{ ._, mnem: {
7464 if (mnem_size) |_| {8429 if (mnem_size) |_| {
7465 if (std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1])) |mnem| {8430 if (std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1])) |mnem| {
7466 break :mnem mnem;8431 break :mnem mnem;
...@@ -7468,7 +8433,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -7468,7 +8433,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
7468 }8433 }
7469 break :mnem std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse8434 break :mnem std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse
7470 return self.fail("Invalid mnemonic: '{s}'", .{mnem_str});8435 return self.fail("Invalid mnemonic: '{s}'", .{mnem_str});
7471 };8436 } };
74728437
7473 var op_it = mem.tokenize(u8, mnem_it.rest(), ",");8438 var op_it = mem.tokenize(u8, mnem_it.rest(), ",");
7474 var ops = [1]encoder.Instruction.Operand{.none} ** 4;8439 var ops = [1]encoder.Instruction.Operand{.none} ** 4;
...@@ -7519,51 +8484,51 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -7519,51 +8484,51 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
7519 } else if (op_it.next()) |op_str| return self.fail("Extra operand: '{s}'", .{op_str});8484 } else if (op_it.next()) |op_str| return self.fail("Extra operand: '{s}'", .{op_str});
75208485
7521 (switch (ops[0]) {8486 (switch (ops[0]) {
7522 .none => self.asmOpOnly(mnem),8487 .none => self.asmOpOnly(mnem_tag),
7523 .reg => |reg0| switch (ops[1]) {8488 .reg => |reg0| switch (ops[1]) {
7524 .none => self.asmRegister(mnem, reg0),8489 .none => self.asmRegister(mnem_tag, reg0),
7525 .reg => |reg1| switch (ops[2]) {8490 .reg => |reg1| switch (ops[2]) {
7526 .none => self.asmRegisterRegister(mnem, reg1, reg0),8491 .none => self.asmRegisterRegister(mnem_tag, reg1, reg0),
7527 .reg => |reg2| switch (ops[3]) {8492 .reg => |reg2| switch (ops[3]) {
7528 .none => self.asmRegisterRegisterRegister(mnem, reg2, reg1, reg0),8493 .none => self.asmRegisterRegisterRegister(mnem_tag, reg2, reg1, reg0),
7529 else => error.InvalidInstruction,8494 else => error.InvalidInstruction,
7530 },8495 },
7531 .mem => |mem2| switch (ops[3]) {8496 .mem => |mem2| switch (ops[3]) {
7532 .none => self.asmMemoryRegisterRegister(mnem, mem2, reg1, reg0),8497 .none => self.asmMemoryRegisterRegister(mnem_tag, mem2, reg1, reg0),
7533 else => error.InvalidInstruction,8498 else => error.InvalidInstruction,
7534 },8499 },
7535 else => error.InvalidInstruction,8500 else => error.InvalidInstruction,
7536 },8501 },
7537 .mem => |mem1| switch (ops[2]) {8502 .mem => |mem1| switch (ops[2]) {
7538 .none => self.asmMemoryRegister(mnem, mem1, reg0),8503 .none => self.asmMemoryRegister(mnem_tag, mem1, reg0),
7539 else => error.InvalidInstruction,8504 else => error.InvalidInstruction,
7540 },8505 },
7541 else => error.InvalidInstruction,8506 else => error.InvalidInstruction,
7542 },8507 },
7543 .mem => |mem0| switch (ops[1]) {8508 .mem => |mem0| switch (ops[1]) {
7544 .none => self.asmMemory(mnem, mem0),8509 .none => self.asmMemory(mnem_tag, mem0),
7545 .reg => |reg1| switch (ops[2]) {8510 .reg => |reg1| switch (ops[2]) {
7546 .none => self.asmRegisterMemory(mnem, reg1, mem0),8511 .none => self.asmRegisterMemory(mnem_tag, reg1, mem0),
7547 else => error.InvalidInstruction,8512 else => error.InvalidInstruction,
7548 },8513 },
7549 else => error.InvalidInstruction,8514 else => error.InvalidInstruction,
7550 },8515 },
7551 .imm => |imm0| switch (ops[1]) {8516 .imm => |imm0| switch (ops[1]) {
7552 .none => self.asmImmediate(mnem, imm0),8517 .none => self.asmImmediate(mnem_tag, imm0),
7553 .reg => |reg1| switch (ops[2]) {8518 .reg => |reg1| switch (ops[2]) {
7554 .none => self.asmRegisterImmediate(mnem, reg1, imm0),8519 .none => self.asmRegisterImmediate(mnem_tag, reg1, imm0),
7555 .reg => |reg2| switch (ops[3]) {8520 .reg => |reg2| switch (ops[3]) {
7556 .none => self.asmRegisterRegisterImmediate(mnem, reg2, reg1, imm0),8521 .none => self.asmRegisterRegisterImmediate(mnem_tag, reg2, reg1, imm0),
7557 else => error.InvalidInstruction,8522 else => error.InvalidInstruction,
7558 },8523 },
7559 .mem => |mem2| switch (ops[3]) {8524 .mem => |mem2| switch (ops[3]) {
7560 .none => self.asmMemoryRegisterImmediate(mnem, mem2, reg1, imm0),8525 .none => self.asmMemoryRegisterImmediate(mnem_tag, mem2, reg1, imm0),
7561 else => error.InvalidInstruction,8526 else => error.InvalidInstruction,
7562 },8527 },
7563 else => error.InvalidInstruction,8528 else => error.InvalidInstruction,
7564 },8529 },
7565 .mem => |mem1| switch (ops[2]) {8530 .mem => |mem1| switch (ops[2]) {
7566 .none => self.asmMemoryImmediate(mnem, mem1, imm0),8531 .none => self.asmMemoryImmediate(mnem_tag, mem1, imm0),
7567 else => error.InvalidInstruction,8532 else => error.InvalidInstruction,
7568 },8533 },
7569 else => error.InvalidInstruction,8534 else => error.InvalidInstruction,
...@@ -7572,7 +8537,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -7572,7 +8537,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
7572 error.InvalidInstruction => return self.fail(8537 error.InvalidInstruction => return self.fail(
7573 "Invalid instruction: '{s} {s} {s} {s} {s}'",8538 "Invalid instruction: '{s} {s} {s} {s} {s}'",
7574 .{8539 .{
7575 @tagName(mnem),8540 @tagName(mnem_tag[1]),
7576 @tagName(ops[0]),8541 @tagName(ops[0]),
7577 @tagName(ops[1]),8542 @tagName(ops[1]),
7578 @tagName(ops[2]),8543 @tagName(ops[2]),
...@@ -7603,19 +8568,55 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -7603,19 +8568,55 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
7603 return self.finishAirResult(inst, result);8568 return self.finishAirResult(inst, result);
7604}8569}
76058570
7606fn movMirTag(self: *Self, ty: Type) !Mir.Inst.Tag {8571fn movMirTag(self: *Self, ty: Type, aligned: bool) !Mir.Inst.FixedTag {
7607 return switch (ty.zigTypeTag()) {8572 switch (ty.zigTypeTag()) {
7608 else => .mov,8573 else => return .{ ._, .mov },
7609 .Float => switch (ty.floatBits(self.target.*)) {8574 .Float => switch (ty.floatBits(self.target.*)) {
7610 16 => unreachable, // needs special handling8575 16 => unreachable, // needs special handling
7611 32 => .movss,8576 32 => return if (self.hasFeature(.avx)) .{ .v_ss, .mov } else .{ ._ss, .mov },
7612 64 => .movsd,8577 64 => return if (self.hasFeature(.avx)) .{ .v_sd, .mov } else .{ ._sd, .mov },
7613 128 => .movaps,8578 128 => return if (self.hasFeature(.avx))
7614 else => return self.fail("TODO movMirTag from {}", .{8579 if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu }
7615 ty.fmt(self.bin_file.options.module.?),8580 else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu },
7616 }),8581 else => {},
7617 },8582 },
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.?)});
7619}8620}
76208621
7621fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void {8622fn 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...@@ -7685,7 +8686,8 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError
76858686
7686fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerError!void {8687fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerError!void {
7687 const abi_size = @intCast(u32, ty.abiSize(self.target.*));8688 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", .{});
7689 switch (src_mcv) {8691 switch (src_mcv) {
7690 .none,8692 .none,
7691 .unreach,8693 .unreach,
...@@ -7700,19 +8702,19 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -7700,19 +8702,19 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
7700 if (imm == 0) {8702 if (imm == 0) {
7701 // 32-bit moves zero-extend to 64-bit, so xoring the 32-bit8703 // 32-bit moves zero-extend to 64-bit, so xoring the 32-bit
7702 // register is the fastest way to zero a register.8704 // 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());
7704 } else if (abi_size > 4 and math.cast(u32, imm) != null) {8706 } else if (abi_size > 4 and math.cast(u32, imm) != null) {
7705 // 32-bit moves zero-extend to 64-bit.8707 // 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));
7707 } else if (abi_size <= 4 and @bitCast(i64, imm) < 0) {8709 } else if (abi_size <= 4 and @bitCast(i64, imm) < 0) {
7708 try self.asmRegisterImmediate(8710 try self.asmRegisterImmediate(
7709 .mov,8711 .{ ._, .mov },
7710 registerAlias(dst_reg, abi_size),8712 registerAlias(dst_reg, abi_size),
7711 Immediate.s(@intCast(i32, @bitCast(i64, imm))),8713 Immediate.s(@intCast(i32, @bitCast(i64, imm))),
7712 );8714 );
7713 } else {8715 } else {
7714 try self.asmRegisterImmediate(8716 try self.asmRegisterImmediate(
7715 .mov,8717 .{ ._, .mov },
7716 registerAlias(dst_reg, abi_size),8718 registerAlias(dst_reg, abi_size),
7717 Immediate.u(imm),8719 Immediate.u(imm),
7718 );8720 );
...@@ -7721,18 +8723,18 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -7721,18 +8723,18 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
7721 .register => |src_reg| if (dst_reg.id() != src_reg.id()) try self.asmRegisterRegister(8723 .register => |src_reg| if (dst_reg.id() != src_reg.id()) try self.asmRegisterRegister(
7722 if ((dst_reg.class() == .floating_point) == (src_reg.class() == .floating_point))8724 if ((dst_reg.class() == .floating_point) == (src_reg.class() == .floating_point))
7723 switch (ty.zigTypeTag()) {8725 switch (ty.zigTypeTag()) {
7724 else => .mov,8726 else => .{ ._, .mov },
7725 .Float, .Vector => .movaps,8727 .Float, .Vector => .{ ._ps, .mova },
7726 }8728 }
7727 else switch (abi_size) {8729 else switch (abi_size) {
7728 2 => return try self.asmRegisterRegisterImmediate(8730 2 => return try self.asmRegisterRegisterImmediate(
7729 if (dst_reg.class() == .floating_point) .pinsrw else .pextrw,8731 if (dst_reg.class() == .floating_point) .{ .p_w, .insr } else .{ .p_w, .extr },
7730 registerAlias(dst_reg, abi_size),8732 registerAlias(dst_reg, 4),
7731 registerAlias(src_reg, abi_size),8733 registerAlias(src_reg, 4),
7732 Immediate.u(0),8734 Immediate.u(0),
7733 ),8735 ),
7734 4 => .movd,8736 4 => .{ ._d, .mov },
7735 8 => .movq,8737 8 => .{ ._q, .mov },
7736 else => return self.fail(8738 else => return self.fail(
7737 "unsupported register copy from {s} to {s}",8739 "unsupported register copy from {s} to {s}",
7738 .{ @tagName(src_reg), @tagName(dst_reg) },8740 .{ @tagName(src_reg), @tagName(dst_reg) },
...@@ -7759,7 +8761,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -7759,7 +8761,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
7759 });8761 });
7760 if (ty.isRuntimeFloat() and ty.floatBits(self.target.*) == 16)8762 if (ty.isRuntimeFloat() and ty.floatBits(self.target.*) == 16)
7761 try self.asmRegisterMemoryImmediate(8763 try self.asmRegisterMemoryImmediate(
7762 .pinsrw,8764 .{ .p_w, .insr },
7763 registerAlias(dst_reg, abi_size),8765 registerAlias(dst_reg, abi_size),
7764 src_mem,8766 src_mem,
7765 Immediate.u(0),8767 Immediate.u(0),
...@@ -7769,10 +8771,14 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -7769,10 +8771,14 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
7769 switch (src_mcv) {8771 switch (src_mcv) {
7770 .register_offset => |reg_off| switch (reg_off.off) {8772 .register_offset => |reg_off| switch (reg_off.off) {
7771 0 => return self.genSetReg(dst_reg, ty, .{ .register = reg_off.reg }),8773 0 => return self.genSetReg(dst_reg, ty, .{ .register = reg_off.reg }),
7772 else => .lea,8774 else => .{ ._, .lea },
7773 },8775 },
7774 .indirect, .load_frame => try self.movMirTag(ty),8776 .indirect => try self.movMirTag(ty, false),
7775 .lea_frame => .lea,8777 .load_frame => |frame_addr| try self.movMirTag(
8778 ty,
8779 self.getFrameAddrAlignment(frame_addr) >= ty.abiAlignment(self.target.*),
8780 ),
8781 .lea_frame => .{ ._, .lea },
7776 else => unreachable,8782 else => unreachable,
7777 },8783 },
7778 registerAlias(dst_reg, abi_size),8784 registerAlias(dst_reg, abi_size),
...@@ -7788,14 +8794,18 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -7788,14 +8794,18 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
7788 });8794 });
7789 return if (ty.isRuntimeFloat() and ty.floatBits(self.target.*) == 16)8795 return if (ty.isRuntimeFloat() and ty.floatBits(self.target.*) == 16)
7790 self.asmRegisterMemoryImmediate(8796 self.asmRegisterMemoryImmediate(
7791 .pinsrw,8797 .{ .p_w, .insr },
7792 registerAlias(dst_reg, abi_size),8798 registerAlias(dst_reg, abi_size),
7793 src_mem,8799 src_mem,
7794 Immediate.u(0),8800 Immediate.u(0),
7795 )8801 )
7796 else8802 else
7797 self.asmRegisterMemory(8803 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 )),
7799 registerAlias(dst_reg, abi_size),8809 registerAlias(dst_reg, abi_size),
7800 src_mem,8810 src_mem,
7801 );8811 );
...@@ -7803,13 +8813,15 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -7803,13 +8813,15 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
7803 .load_direct => |sym_index| if (!ty.isRuntimeFloat()) {8813 .load_direct => |sym_index| if (!ty.isRuntimeFloat()) {
7804 const atom_index = try self.owner.getSymbolIndex(self);8814 const atom_index = try self.owner.getSymbolIndex(self);
7805 _ = try self.addInst(.{8815 _ = try self.addInst(.{
7806 .tag = .mov_linker,8816 .tag = .mov,
7807 .ops = .direct_reloc,8817 .ops = .direct_reloc,
7808 .data = .{ .payload = try self.addExtra(Mir.LeaRegisterReloc{8818 .data = .{ .rx = .{
7809 .reg = @enumToInt(dst_reg.to64()),8819 .r1 = dst_reg.to64(),
7810 .atom_index = atom_index,8820 .payload = try self.addExtra(Mir.Reloc{
7811 .sym_index = sym_index,8821 .atom_index = atom_index,
7812 }) },8822 .sym_index = sym_index,
8823 }),
8824 } },
7813 });8825 });
7814 return;8826 return;
7815 },8827 },
...@@ -7826,14 +8838,14 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -7826,14 +8838,14 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
7826 });8838 });
7827 if (ty.isRuntimeFloat() and ty.floatBits(self.target.*) == 16)8839 if (ty.isRuntimeFloat() and ty.floatBits(self.target.*) == 16)
7828 try self.asmRegisterMemoryImmediate(8840 try self.asmRegisterMemoryImmediate(
7829 .pinsrw,8841 .{ .p_w, .insr },
7830 registerAlias(dst_reg, abi_size),8842 registerAlias(dst_reg, abi_size),
7831 src_mem,8843 src_mem,
7832 Immediate.u(0),8844 Immediate.u(0),
7833 )8845 )
7834 else8846 else
7835 try self.asmRegisterMemory(8847 try self.asmRegisterMemory(
7836 try self.movMirTag(ty),8848 try self.movMirTag(ty, false),
7837 registerAlias(dst_reg, abi_size),8849 registerAlias(dst_reg, abi_size),
7838 src_mem,8850 src_mem,
7839 );8851 );
...@@ -7842,8 +8854,8 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -7842,8 +8854,8 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
7842 const atom_index = try self.owner.getSymbolIndex(self);8854 const atom_index = try self.owner.getSymbolIndex(self);
7843 _ = try self.addInst(.{8855 _ = try self.addInst(.{
7844 .tag = switch (src_mcv) {8856 .tag = switch (src_mcv) {
7845 .lea_direct => .lea_linker,8857 .lea_direct => .lea,
7846 .lea_got => .mov_linker,8858 .lea_got => .mov,
7847 else => unreachable,8859 else => unreachable,
7848 },8860 },
7849 .ops = switch (src_mcv) {8861 .ops = switch (src_mcv) {
...@@ -7851,27 +8863,31 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -7851,27 +8863,31 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
7851 .lea_got => .got_reloc,8863 .lea_got => .got_reloc,
7852 else => unreachable,8864 else => unreachable,
7853 },8865 },
7854 .data = .{ .payload = try self.addExtra(Mir.LeaRegisterReloc{8866 .data = .{ .rx = .{
7855 .reg = @enumToInt(dst_reg.to64()),8867 .r1 = dst_reg.to64(),
7856 .atom_index = atom_index,8868 .payload = try self.addExtra(Mir.Reloc{
7857 .sym_index = sym_index,8869 .atom_index = atom_index,
7858 }) },8870 .sym_index = sym_index,
8871 }),
8872 } },
7859 });8873 });
7860 },8874 },
7861 .lea_tlv => |sym_index| {8875 .lea_tlv => |sym_index| {
7862 const atom_index = try self.owner.getSymbolIndex(self);8876 const atom_index = try self.owner.getSymbolIndex(self);
7863 if (self.bin_file.cast(link.File.MachO)) |_| {8877 if (self.bin_file.cast(link.File.MachO)) |_| {
7864 _ = try self.addInst(.{8878 _ = try self.addInst(.{
7865 .tag = .lea_linker,8879 .tag = .lea,
7866 .ops = .tlv_reloc,8880 .ops = .tlv_reloc,
7867 .data = .{ .payload = try self.addExtra(Mir.LeaRegisterReloc{8881 .data = .{ .rx = .{
7868 .reg = @enumToInt(Register.rdi),8882 .r1 = .rdi,
7869 .atom_index = atom_index,8883 .payload = try self.addExtra(Mir.Reloc{
7870 .sym_index = sym_index,8884 .atom_index = atom_index,
7871 }) },8885 .sym_index = sym_index,
8886 }),
8887 } },
7872 });8888 });
7873 // TODO: spill registers before calling8889 // 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 } }));
7875 try self.genSetReg(dst_reg.to64(), Type.usize, .{ .register = .rax });8891 try self.genSetReg(dst_reg.to64(), Type.usize, .{ .register = .rax });
7876 } else return self.fail("TODO emit ptr to TLV sequence on {s}", .{8892 } else return self.fail("TODO emit ptr to TLV sequence on {s}", .{
7877 @tagName(self.bin_file.tag),8893 @tagName(self.bin_file.tag),
...@@ -7898,7 +8914,7 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal...@@ -7898,7 +8914,7 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
7898 else8914 else
7899 Immediate.u(@intCast(u32, imm));8915 Immediate.u(@intCast(u32, imm));
7900 try self.asmMemoryImmediate(8916 try self.asmMemoryImmediate(
7901 .mov,8917 .{ ._, .mov },
7902 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = base, .disp = disp }),8918 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = base, .disp = disp }),
7903 immediate,8919 immediate,
7904 );8920 );
...@@ -7906,14 +8922,14 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal...@@ -7906,14 +8922,14 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
7906 3, 5...7 => unreachable,8922 3, 5...7 => unreachable,
7907 else => if (math.cast(i32, @bitCast(i64, imm))) |small| {8923 else => if (math.cast(i32, @bitCast(i64, imm))) |small| {
7908 try self.asmMemoryImmediate(8924 try self.asmMemoryImmediate(
7909 .mov,8925 .{ ._, .mov },
7910 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = base, .disp = disp }),8926 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = base, .disp = disp }),
7911 Immediate.s(small),8927 Immediate.s(small),
7912 );8928 );
7913 } else {8929 } else {
7914 var offset: i32 = 0;8930 var offset: i32 = 0;
7915 while (offset < abi_size) : (offset += 4) try self.asmMemoryImmediate(8931 while (offset < abi_size) : (offset += 4) try self.asmMemoryImmediate(
7916 .mov,8932 .{ ._, .mov },
7917 Memory.sib(.dword, .{ .base = base, .disp = disp + offset }),8933 Memory.sib(.dword, .{ .base = base, .disp = disp + offset }),
7918 if (ty.isSignedInt())8934 if (ty.isSignedInt())
7919 Immediate.s(@truncate(8935 Immediate.s(@truncate(
...@@ -7936,14 +8952,31 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal...@@ -7936,14 +8952,31 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
7936 );8952 );
7937 if (ty.isRuntimeFloat() and ty.floatBits(self.target.*) == 16)8953 if (ty.isRuntimeFloat() and ty.floatBits(self.target.*) == 16)
7938 try self.asmMemoryRegisterImmediate(8954 try self.asmMemoryRegisterImmediate(
7939 .pextrw,8955 .{ .p_w, .extr },
7940 dst_mem,8956 dst_mem,
7941 registerAlias(src_reg, abi_size),8957 src_reg.to128(),
7942 Immediate.u(0),8958 Immediate.u(0),
7943 )8959 )
7944 else8960 else
7945 try self.asmMemoryRegister(8961 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 }),
7947 dst_mem,8980 dst_mem,
7948 registerAlias(src_reg, abi_size),8981 registerAlias(src_reg, abi_size),
7949 );8982 );
...@@ -8015,7 +9048,7 @@ fn genInlineMemcpyRegisterRegister(...@@ -8015,7 +9048,7 @@ fn genInlineMemcpyRegisterRegister(
8015 while (remainder > 0) {9048 while (remainder > 0) {
8016 const nearest_power_of_two = @as(u6, 1) << math.log2_int(u3, @intCast(u3, remainder));9049 const nearest_power_of_two = @as(u6, 1) << math.log2_int(u3, @intCast(u3, remainder));
8017 try self.asmMemoryRegister(9050 try self.asmMemoryRegister(
8018 .mov,9051 .{ ._, .mov },
8019 Memory.sib(Memory.PtrSize.fromSize(nearest_power_of_two), .{9052 Memory.sib(Memory.PtrSize.fromSize(nearest_power_of_two), .{
8020 .base = dst_reg,9053 .base = dst_reg,
8021 .disp = -next_offset,9054 .disp = -next_offset,
...@@ -8024,7 +9057,7 @@ fn genInlineMemcpyRegisterRegister(...@@ -8024,7 +9057,7 @@ fn genInlineMemcpyRegisterRegister(
8024 );9057 );
80259058
8026 if (nearest_power_of_two > 1) {9059 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 }, .{
8028 .immediate = nearest_power_of_two * 8,9061 .immediate = nearest_power_of_two * 8,
8029 });9062 });
8030 }9063 }
...@@ -8035,8 +9068,8 @@ fn genInlineMemcpyRegisterRegister(...@@ -8035,8 +9068,8 @@ fn genInlineMemcpyRegisterRegister(
8035 } else {9068 } else {
8036 try self.asmMemoryRegister(9069 try self.asmMemoryRegister(
8037 switch (src_reg.class()) {9070 switch (src_reg.class()) {
8038 .general_purpose, .segment => .mov,9071 .general_purpose, .segment => .{ ._, .mov },
8039 .floating_point => .movss,9072 .floating_point => .{ ._ss, .mov },
8040 },9073 },
8041 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = dst_reg, .disp = -offset }),9074 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = dst_reg, .disp = -offset }),
8042 registerAlias(src_reg, abi_size),9075 registerAlias(src_reg, abi_size),
...@@ -8049,11 +9082,7 @@ fn genInlineMemcpy(self: *Self, dst_ptr: MCValue, src_ptr: MCValue, len: MCValue...@@ -8049,11 +9082,7 @@ fn genInlineMemcpy(self: *Self, dst_ptr: MCValue, src_ptr: MCValue, len: MCValue
8049 try self.genSetReg(.rdi, Type.usize, dst_ptr);9082 try self.genSetReg(.rdi, Type.usize, dst_ptr);
8050 try self.genSetReg(.rsi, Type.usize, src_ptr);9083 try self.genSetReg(.rsi, Type.usize, src_ptr);
8051 try self.genSetReg(.rcx, Type.usize, len);9084 try self.genSetReg(.rcx, Type.usize, len);
8052 _ = try self.addInst(.{9085 try self.asmOpOnly(.{ .@"rep _sb", .mov });
8053 .tag = .movs,
8054 .ops = .string,
8055 .data = .{ .string = .{ .repeat = .rep, .width = .b } },
8056 });
8057}9086}
80589087
8059fn genInlineMemset(self: *Self, dst_ptr: MCValue, value: MCValue, len: MCValue) InnerError!void {9088fn 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)...@@ -8061,11 +9090,7 @@ fn genInlineMemset(self: *Self, dst_ptr: MCValue, value: MCValue, len: MCValue)
8061 try self.genSetReg(.rdi, Type.usize, dst_ptr);9090 try self.genSetReg(.rdi, Type.usize, dst_ptr);
8062 try self.genSetReg(.al, Type.u8, value);9091 try self.genSetReg(.al, Type.u8, value);
8063 try self.genSetReg(.rcx, Type.usize, len);9092 try self.genSetReg(.rcx, Type.usize, len);
8064 _ = try self.addInst(.{9093 try self.asmOpOnly(.{ .@"rep _sb", .sto });
8065 .tag = .stos,
8066 .ops = .string,
8067 .data = .{ .string = .{ .repeat = .rep, .width = .b } },
8068 });
8069}9094}
80709095
8071fn genLazySymbolRef(9096fn genLazySymbolRef(
...@@ -8083,14 +9108,14 @@ fn genLazySymbolRef(...@@ -8083,14 +9108,14 @@ fn genLazySymbolRef(
8083 const got_mem =9108 const got_mem =
8084 Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) });9109 Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) });
8085 switch (tag) {9110 switch (tag) {
8086 .lea, .mov => try self.asmRegisterMemory(.mov, reg.to64(), got_mem),9111 .lea, .mov => try self.asmRegisterMemory(.{ ._, .mov }, reg.to64(), got_mem),
8087 .call => try self.asmMemory(.call, got_mem),9112 .call => try self.asmMemory(.{ ._, .call }, got_mem),
8088 else => unreachable,9113 else => unreachable,
8089 }9114 }
8090 switch (tag) {9115 switch (tag) {
8091 .lea, .call => {},9116 .lea, .call => {},
8092 .mov => try self.asmRegisterMemory(9117 .mov => try self.asmRegisterMemory(
8093 tag,9118 .{ ._, tag },
8094 reg.to64(),9119 reg.to64(),
8095 Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }),9120 Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }),
8096 ),9121 ),
...@@ -8107,7 +9132,7 @@ fn genLazySymbolRef(...@@ -8107,7 +9132,7 @@ fn genLazySymbolRef(
8107 }9132 }
8108 switch (tag) {9133 switch (tag) {
8109 .lea, .mov => {},9134 .lea, .mov => {},
8110 .call => try self.asmRegister(.call, reg),9135 .call => try self.asmRegister(.{ ._, .call }, reg),
8111 else => unreachable,9136 else => unreachable,
8112 }9137 }
8113 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {9138 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
...@@ -8121,7 +9146,7 @@ fn genLazySymbolRef(...@@ -8121,7 +9146,7 @@ fn genLazySymbolRef(
8121 }9146 }
8122 switch (tag) {9147 switch (tag) {
8123 .lea, .mov => {},9148 .lea, .mov => {},
8124 .call => try self.asmRegister(.call, reg),9149 .call => try self.asmRegister(.{ ._, .call }, reg),
8125 else => unreachable,9150 else => unreachable,
8126 }9151 }
8127 } else {9152 } else {
...@@ -8164,7 +9189,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -8164,7 +9189,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
8164 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);9189 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
81659190
8166 const dest = try self.allocRegOrMem(inst, true);9191 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);
8168 break :result dest;9193 break :result dest;
8169 };9194 };
8170 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });9195 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -8226,13 +9251,13 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void {...@@ -8226,13 +9251,13 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void {
82269251
8227 try self.asmRegisterRegister(switch (dst_ty.floatBits(self.target.*)) {9252 try self.asmRegisterRegister(switch (dst_ty.floatBits(self.target.*)) {
8228 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse))9253 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse))
8229 .cvtsi2ss9254 .{ ._, .cvtsi2ss }
8230 else9255 else
8231 return self.fail("TODO implement airIntToFloat from {} to {} without sse", .{9256 return self.fail("TODO implement airIntToFloat from {} to {} without sse", .{
8232 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),9257 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
8233 }),9258 }),
8234 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2))9259 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2))
8235 .cvtsi2sd9260 .{ ._, .cvtsi2sd }
8236 else9261 else
8237 return self.fail("TODO implement airIntToFloat from {} to {} without sse2", .{9262 return self.fail("TODO implement airIntToFloat from {} to {} without sse2", .{
8238 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),9263 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 {...@@ -8272,7 +9297,7 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {
8272 },9297 },
8273 };9298 };
8274 try self.asmMemory(9299 try self.asmMemory(
8275 .fld,9300 .{ .f_, .ld },
8276 Memory.sib(Memory.PtrSize.fromSize(src_abi_size), .{9301 Memory.sib(Memory.PtrSize.fromSize(src_abi_size), .{
8277 .base = .{ .frame = frame_addr.index },9302 .base = .{ .frame = frame_addr.index },
8278 .disp = frame_addr.off,9303 .disp = frame_addr.off,
...@@ -8282,7 +9307,7 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {...@@ -8282,7 +9307,7 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {
8282 // convert9307 // convert
8283 const stack_dst = try self.allocRegOrMem(inst, false);9308 const stack_dst = try self.allocRegOrMem(inst, false);
8284 try self.asmMemory(9309 try self.asmMemory(
8285 .fisttp,9310 .{ .f_p, .istt },
8286 Memory.sib(Memory.PtrSize.fromSize(dst_abi_size), .{9311 Memory.sib(Memory.PtrSize.fromSize(dst_abi_size), .{
8287 .base = .{ .frame = stack_dst.load_frame.index },9312 .base = .{ .frame = stack_dst.load_frame.index },
8288 .disp = stack_dst.load_frame.off,9313 .disp = stack_dst.load_frame.off,
...@@ -8338,16 +9363,11 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {...@@ -8338,16 +9363,11 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
8338 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);9363 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
83399364
8340 try self.spillEflagsIfOccupied();9365 try self.spillEflagsIfOccupied();
8341 if (val_abi_size <= 8) {9366 if (val_abi_size <= 8) try self.asmMemoryRegister(
8342 _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{9367 .{ .@"lock _", .cmpxchg },
8343 .r = registerAlias(new_reg.?, val_abi_size),9368 ptr_mem,
8344 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),9369 registerAlias(new_reg.?, val_abi_size),
8345 } } });9370 ) else try self.asmMemory(.{ .@"lock _16b", .cmpxchg }, ptr_mem);
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 }
83519371
8352 const result: MCValue = result: {9372 const result: MCValue = result: {
8353 if (self.liveness.isUnused(inst)) break :result .unreach;9373 if (self.liveness.isUnused(inst)) break :result .unreach;
...@@ -8445,16 +9465,17 @@ fn atomicOp(...@@ -8445,16 +9465,17 @@ fn atomicOp(
84459465
8446 try self.genSetReg(dst_reg, val_ty, val_mcv);9466 try self.genSetReg(dst_reg, val_ty, val_mcv);
8447 if (rmw_op == std.builtin.AtomicRmwOp.Sub and tag == .xadd) {9467 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);
8449 }9469 }
8450 _ = try self.addInst(.{ .tag = tag, .ops = switch (tag) {9470 try self.asmMemoryRegister(
8451 .mov, .xchg => .mr_sib,9471 switch (tag) {
8452 .xadd, .add, .sub, .@"and", .@"or", .xor => .lock_mr_sib,9472 .mov, .xchg => .{ ._, tag },
8453 else => unreachable,9473 .xadd, .add, .sub, .@"and", .@"or", .xor => .{ .@"lock _", tag },
8454 }, .data = .{ .rx = .{9474 else => unreachable,
8455 .r = registerAlias(dst_reg, val_abi_size),9475 },
8456 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),9476 ptr_mem,
8457 } } });9477 registerAlias(dst_reg, val_abi_size),
9478 );
84589479
8459 return if (unused) .unreach else dst_mcv;9480 return if (unused) .unreach else dst_mcv;
8460 },9481 },
...@@ -8464,22 +9485,22 @@ fn atomicOp(...@@ -8464,22 +9485,22 @@ fn atomicOp(
8464 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);9485 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
8465 defer self.register_manager.unlockReg(tmp_lock);9486 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);
8468 const loop = @intCast(u32, self.mir_instructions.len);9489 const loop = @intCast(u32, self.mir_instructions.len);
8469 if (rmw_op != std.builtin.AtomicRmwOp.Xchg) {9490 if (rmw_op != std.builtin.AtomicRmwOp.Xchg) {
8470 try self.genSetReg(tmp_reg, val_ty, .{ .register = .rax });9491 try self.genSetReg(tmp_reg, val_ty, .{ .register = .rax });
8471 }9492 }
8472 if (rmw_op) |op| switch (op) {9493 if (rmw_op) |op| switch (op) {
8473 .Xchg => try self.genSetReg(tmp_reg, val_ty, val_mcv),9494 .Xchg => try self.genSetReg(tmp_reg, val_ty, val_mcv),
8474 .Add => try self.genBinOpMir(.add, val_ty, tmp_mcv, val_mcv),9495 .Add => try self.genBinOpMir(.{ ._, .add }, val_ty, tmp_mcv, val_mcv),
8475 .Sub => try self.genBinOpMir(.sub, val_ty, tmp_mcv, val_mcv),9496 .Sub => try self.genBinOpMir(.{ ._, .sub }, val_ty, tmp_mcv, val_mcv),
8476 .And => try self.genBinOpMir(.@"and", val_ty, tmp_mcv, val_mcv),9497 .And => try self.genBinOpMir(.{ ._, .@"and" }, val_ty, tmp_mcv, val_mcv),
8477 .Nand => {9498 .Nand => {
8478 try self.genBinOpMir(.@"and", val_ty, tmp_mcv, val_mcv);9499 try self.genBinOpMir(.{ ._, .@"and" }, val_ty, tmp_mcv, val_mcv);
8479 try self.genUnOpMir(.not, val_ty, tmp_mcv);9500 try self.genUnOpMir(.{ ._, .not }, val_ty, tmp_mcv);
8480 },9501 },
8481 .Or => try self.genBinOpMir(.@"or", val_ty, tmp_mcv, val_mcv),9502 .Or => try self.genBinOpMir(.{ ._, .@"or" }, val_ty, tmp_mcv, val_mcv),
8482 .Xor => try self.genBinOpMir(.xor, val_ty, tmp_mcv, val_mcv),9503 .Xor => try self.genBinOpMir(.{ ._, .xor }, val_ty, tmp_mcv, val_mcv),
8483 .Min, .Max => {9504 .Min, .Max => {
8484 const cc: Condition = switch (if (val_ty.isAbiInt())9505 const cc: Condition = switch (if (val_ty.isAbiInt())
8485 val_ty.intInfo(self.target.*).signedness9506 val_ty.intInfo(self.target.*).signedness
...@@ -8497,7 +9518,7 @@ fn atomicOp(...@@ -8497,7 +9518,7 @@ fn atomicOp(
8497 },9518 },
8498 };9519 };
84999520
8500 try self.genBinOpMir(.cmp, val_ty, tmp_mcv, val_mcv);9521 try self.genBinOpMir(.{ ._, .cmp }, val_ty, tmp_mcv, val_mcv);
8501 const cmov_abi_size = @max(val_abi_size, 2);9522 const cmov_abi_size = @max(val_abi_size, 2);
8502 switch (val_mcv) {9523 switch (val_mcv) {
8503 .register => |val_reg| try self.asmCmovccRegisterRegister(9524 .register => |val_reg| try self.asmCmovccRegisterRegister(
...@@ -8521,19 +9542,20 @@ fn atomicOp(...@@ -8521,19 +9542,20 @@ fn atomicOp(
8521 }9542 }
8522 },9543 },
8523 };9544 };
8524 _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{9545 try self.asmMemoryRegister(
8525 .r = registerAlias(tmp_reg, val_abi_size),9546 .{ .@"lock _", .cmpxchg },
8526 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),9547 ptr_mem,
8527 } } });9548 registerAlias(tmp_reg, val_abi_size),
9549 );
8528 _ = try self.asmJccReloc(loop, .ne);9550 _ = try self.asmJccReloc(loop, .ne);
8529 return if (unused) .unreach else .{ .register = .rax };9551 return if (unused) .unreach else .{ .register = .rax };
8530 } else {9552 } else {
8531 try self.asmRegisterMemory(.mov, .rax, Memory.sib(.qword, .{9553 try self.asmRegisterMemory(.{ ._, .mov }, .rax, Memory.sib(.qword, .{
8532 .base = ptr_mem.sib.base,9554 .base = ptr_mem.sib.base,
8533 .scale_index = ptr_mem.scaleIndex(),9555 .scale_index = ptr_mem.scaleIndex(),
8534 .disp = ptr_mem.sib.disp + 0,9556 .disp = ptr_mem.sib.disp + 0,
8535 }));9557 }));
8536 try self.asmRegisterMemory(.mov, .rdx, Memory.sib(.qword, .{9558 try self.asmRegisterMemory(.{ ._, .mov }, .rdx, Memory.sib(.qword, .{
8537 .base = ptr_mem.sib.base,9559 .base = ptr_mem.sib.base,
8538 .scale_index = ptr_mem.scaleIndex(),9560 .scale_index = ptr_mem.scaleIndex(),
8539 .disp = ptr_mem.sib.disp + 8,9561 .disp = ptr_mem.sib.disp + 8,
...@@ -8548,53 +9570,51 @@ fn atomicOp(...@@ -8548,53 +9570,51 @@ fn atomicOp(
8548 const val_lo_mem = val_mem_mcv.mem(.qword);9570 const val_lo_mem = val_mem_mcv.mem(.qword);
8549 const val_hi_mem = val_mem_mcv.address().offset(8).deref().mem(.qword);9571 const val_hi_mem = val_mem_mcv.address().offset(8).deref().mem(.qword);
8550 if (rmw_op != std.builtin.AtomicRmwOp.Xchg) {9572 if (rmw_op != std.builtin.AtomicRmwOp.Xchg) {
8551 try self.asmRegisterRegister(.mov, .rbx, .rax);9573 try self.asmRegisterRegister(.{ ._, .mov }, .rbx, .rax);
8552 try self.asmRegisterRegister(.mov, .rcx, .rdx);9574 try self.asmRegisterRegister(.{ ._, .mov }, .rcx, .rdx);
8553 }9575 }
8554 if (rmw_op) |op| switch (op) {9576 if (rmw_op) |op| switch (op) {
8555 .Xchg => {9577 .Xchg => {
8556 try self.asmRegisterMemory(.mov, .rbx, val_lo_mem);9578 try self.asmRegisterMemory(.{ ._, .mov }, .rbx, val_lo_mem);
8557 try self.asmRegisterMemory(.mov, .rcx, val_hi_mem);9579 try self.asmRegisterMemory(.{ ._, .mov }, .rcx, val_hi_mem);
8558 },9580 },
8559 .Add => {9581 .Add => {
8560 try self.asmRegisterMemory(.add, .rbx, val_lo_mem);9582 try self.asmRegisterMemory(.{ ._, .add }, .rbx, val_lo_mem);
8561 try self.asmRegisterMemory(.adc, .rcx, val_hi_mem);9583 try self.asmRegisterMemory(.{ ._, .adc }, .rcx, val_hi_mem);
8562 },9584 },
8563 .Sub => {9585 .Sub => {
8564 try self.asmRegisterMemory(.sub, .rbx, val_lo_mem);9586 try self.asmRegisterMemory(.{ ._, .sub }, .rbx, val_lo_mem);
8565 try self.asmRegisterMemory(.sbb, .rcx, val_hi_mem);9587 try self.asmRegisterMemory(.{ ._, .sbb }, .rcx, val_hi_mem);
8566 },9588 },
8567 .And => {9589 .And => {
8568 try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem);9590 try self.asmRegisterMemory(.{ ._, .@"and" }, .rbx, val_lo_mem);
8569 try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem);9591 try self.asmRegisterMemory(.{ ._, .@"and" }, .rcx, val_hi_mem);
8570 },9592 },
8571 .Nand => {9593 .Nand => {
8572 try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem);9594 try self.asmRegisterMemory(.{ ._, .@"and" }, .rbx, val_lo_mem);
8573 try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem);9595 try self.asmRegisterMemory(.{ ._, .@"and" }, .rcx, val_hi_mem);
8574 try self.asmRegister(.not, .rbx);9596 try self.asmRegister(.{ ._, .not }, .rbx);
8575 try self.asmRegister(.not, .rcx);9597 try self.asmRegister(.{ ._, .not }, .rcx);
8576 },9598 },
8577 .Or => {9599 .Or => {
8578 try self.asmRegisterMemory(.@"or", .rbx, val_lo_mem);9600 try self.asmRegisterMemory(.{ ._, .@"or" }, .rbx, val_lo_mem);
8579 try self.asmRegisterMemory(.@"or", .rcx, val_hi_mem);9601 try self.asmRegisterMemory(.{ ._, .@"or" }, .rcx, val_hi_mem);
8580 },9602 },
8581 .Xor => {9603 .Xor => {
8582 try self.asmRegisterMemory(.xor, .rbx, val_lo_mem);9604 try self.asmRegisterMemory(.{ ._, .xor }, .rbx, val_lo_mem);
8583 try self.asmRegisterMemory(.xor, .rcx, val_hi_mem);9605 try self.asmRegisterMemory(.{ ._, .xor }, .rcx, val_hi_mem);
8584 },9606 },
8585 else => return self.fail("TODO implement x86 atomic loop for {} {s}", .{9607 else => return self.fail("TODO implement x86 atomic loop for {} {s}", .{
8586 val_ty.fmt(self.bin_file.options.module.?), @tagName(op),9608 val_ty.fmt(self.bin_file.options.module.?), @tagName(op),
8587 }),9609 }),
8588 };9610 };
8589 _ = try self.addInst(.{ .tag = .cmpxchgb, .ops = .lock_m_sib, .data = .{9611 try self.asmMemory(.{ .@"lock _16b", .cmpxchg }, ptr_mem);
8590 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
8591 } });
8592 _ = try self.asmJccReloc(loop, .ne);9612 _ = try self.asmJccReloc(loop, .ne);
85939613
8594 if (unused) return .unreach;9614 if (unused) return .unreach;
8595 const dst_mcv = try self.allocTempRegOrMem(val_ty, false);9615 const dst_mcv = try self.allocTempRegOrMem(val_ty, false);
8596 try self.asmMemoryRegister(9616 try self.asmMemoryRegister(
8597 .mov,9617 .{ ._, .mov },
8598 Memory.sib(.qword, .{9618 Memory.sib(.qword, .{
8599 .base = .{ .frame = dst_mcv.load_frame.index },9619 .base = .{ .frame = dst_mcv.load_frame.index },
8600 .disp = dst_mcv.load_frame.off + 0,9620 .disp = dst_mcv.load_frame.off + 0,
...@@ -8602,7 +9622,7 @@ fn atomicOp(...@@ -8602,7 +9622,7 @@ fn atomicOp(
8602 .rax,9622 .rax,
8603 );9623 );
8604 try self.asmMemoryRegister(9624 try self.asmMemoryRegister(
8605 .mov,9625 .{ ._, .mov },
8606 Memory.sib(.qword, .{9626 Memory.sib(.qword, .{
8607 .base = .{ .frame = dst_mcv.load_frame.index },9627 .base = .{ .frame = dst_mcv.load_frame.index },
8608 .disp = dst_mcv.load_frame.off + 8,9628 .disp = dst_mcv.load_frame.off + 8,
...@@ -8754,8 +9774,13 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {...@@ -8754,8 +9774,13 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
8754 .off = elem_abi_size,9774 .off = elem_abi_size,
8755 } });9775 } });
87569776
8757 try self.genBinOpMir(.sub, Type.usize, len_mcv, .{ .immediate = 1 });9777 try self.genBinOpMir(.{ ._, .sub }, Type.usize, len_mcv, .{ .immediate = 1 });
8758 try self.asmRegisterRegisterImmediate(.imul, len_reg, len_reg, Immediate.u(elem_abi_size));9778 try self.asmRegisterRegisterImmediate(
9779 .{ .i_, .mul },
9780 len_reg,
9781 len_reg,
9782 Immediate.u(elem_abi_size),
9783 );
8759 try self.genInlineMemcpy(second_elem_ptr_mcv, ptr, len_mcv);9784 try self.genInlineMemcpy(second_elem_ptr_mcv, ptr, len_mcv);
87609785
8761 try self.performReloc(skip_reloc);9786 try self.performReloc(skip_reloc);
...@@ -8893,7 +9918,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {...@@ -8893,7 +9918,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
8893 try self.truncateRegister(err_ty, err_reg.to32());9918 try self.truncateRegister(err_ty, err_reg.to32());
88949919
8895 try self.asmRegisterMemory(9920 try self.asmRegisterMemory(
8896 .mov,9921 .{ ._, .mov },
8897 start_reg.to32(),9922 start_reg.to32(),
8898 Memory.sib(.dword, .{9923 Memory.sib(.dword, .{
8899 .base = .{ .reg = addr_reg.to64() },9924 .base = .{ .reg = addr_reg.to64() },
...@@ -8902,7 +9927,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {...@@ -8902,7 +9927,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
8902 }),9927 }),
8903 );9928 );
8904 try self.asmRegisterMemory(9929 try self.asmRegisterMemory(
8905 .mov,9930 .{ ._, .mov },
8906 end_reg.to32(),9931 end_reg.to32(),
8907 Memory.sib(.dword, .{9932 Memory.sib(.dword, .{
8908 .base = .{ .reg = addr_reg.to64() },9933 .base = .{ .reg = addr_reg.to64() },
...@@ -8910,9 +9935,9 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {...@@ -8910,9 +9935,9 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
8910 .disp = 8,9935 .disp = 8,
8911 }),9936 }),
8912 );9937 );
8913 try self.asmRegisterRegister(.sub, end_reg.to32(), start_reg.to32());9938 try self.asmRegisterRegister(.{ ._, .sub }, end_reg.to32(), start_reg.to32());
8914 try self.asmRegisterMemory(9939 try self.asmRegisterMemory(
8915 .lea,9940 .{ ._, .lea },
8916 start_reg.to64(),9941 start_reg.to64(),
8917 Memory.sib(.byte, .{9942 Memory.sib(.byte, .{
8918 .base = .{ .reg = addr_reg.to64() },9943 .base = .{ .reg = addr_reg.to64() },
...@@ -8921,7 +9946,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {...@@ -8921,7 +9946,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
8921 }),9946 }),
8922 );9947 );
8923 try self.asmRegisterMemory(9948 try self.asmRegisterMemory(
8924 .lea,9949 .{ ._, .lea },
8925 end_reg.to32(),9950 end_reg.to32(),
8926 Memory.sib(.byte, .{9951 Memory.sib(.byte, .{
8927 .base = .{ .reg = end_reg.to64() },9952 .base = .{ .reg = end_reg.to64() },
...@@ -8931,7 +9956,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {...@@ -8931,7 +9956,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
89319956
8932 const dst_mcv = try self.allocRegOrMem(inst, false);9957 const dst_mcv = try self.allocRegOrMem(inst, false);
8933 try self.asmMemoryRegister(9958 try self.asmMemoryRegister(
8934 .mov,9959 .{ ._, .mov },
8935 Memory.sib(.qword, .{9960 Memory.sib(.qword, .{
8936 .base = .{ .frame = dst_mcv.load_frame.index },9961 .base = .{ .frame = dst_mcv.load_frame.index },
8937 .disp = dst_mcv.load_frame.off,9962 .disp = dst_mcv.load_frame.off,
...@@ -8939,7 +9964,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {...@@ -8939,7 +9964,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
8939 start_reg.to64(),9964 start_reg.to64(),
8940 );9965 );
8941 try self.asmMemoryRegister(9966 try self.asmMemoryRegister(
8942 .mov,9967 .{ ._, .mov },
8943 Memory.sib(.qword, .{9968 Memory.sib(.qword, .{
8944 .base = .{ .frame = dst_mcv.load_frame.index },9969 .base = .{ .frame = dst_mcv.load_frame.index },
8945 .disp = dst_mcv.load_frame.off + 8,9970 .disp = dst_mcv.load_frame.off + 8,
...@@ -9035,13 +10060,13 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -9035,13 +10060,13 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
9035 try self.truncateRegister(elem_ty, elem_reg);10060 try self.truncateRegister(elem_ty, elem_reg);
9036 }10061 }
9037 if (elem_bit_off > 0) try self.genShiftBinOpMir(10062 if (elem_bit_off > 0) try self.genShiftBinOpMir(
9038 .shl,10063 .{ ._l, .sh },
9039 elem_ty,10064 elem_ty,
9040 .{ .register = elem_reg },10065 .{ .register = elem_reg },
9041 .{ .immediate = elem_bit_off },10066 .{ .immediate = elem_bit_off },
9042 );10067 );
9043 try self.genBinOpMir(10068 try self.genBinOpMir(
9044 .@"or",10069 .{ ._, .@"or" },
9045 elem_ty,10070 elem_ty,
9046 .{ .load_frame = .{ .index = frame_index, .off = elem_byte_off } },10071 .{ .load_frame = .{ .index = frame_index, .off = elem_byte_off } },
9047 .{ .register = elem_reg },10072 .{ .register = elem_reg },
...@@ -9052,13 +10077,13 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -9052,13 +10077,13 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
9052 try self.truncateRegister(elem_ty, registerAlias(reg, elem_abi_size));10077 try self.truncateRegister(elem_ty, registerAlias(reg, elem_abi_size));
9053 }10078 }
9054 try self.genShiftBinOpMir(10079 try self.genShiftBinOpMir(
9055 .shr,10080 .{ ._r, .sh },
9056 elem_ty,10081 elem_ty,
9057 .{ .register = reg },10082 .{ .register = reg },
9058 .{ .immediate = elem_abi_bits - elem_bit_off },10083 .{ .immediate = elem_abi_bits - elem_bit_off },
9059 );10084 );
9060 try self.genBinOpMir(10085 try self.genBinOpMir(
9061 .@"or",10086 .{ ._, .@"or" },
9062 elem_ty,10087 elem_ty,
9063 .{ .load_frame = .{10088 .{ .load_frame = .{
9064 .index = frame_index,10089 .index = frame_index,
...@@ -9130,9 +10155,150 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {...@@ -9130,9 +10155,150 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {
9130fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void {10155fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void {
9131 const pl_op = self.air.instructions.items(.data)[inst].pl_op;10156 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
9132 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;10157 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
9133 _ = extra;10158 const ty = self.air.typeOfIndex(inst);
9134 return self.fail("TODO implement airMulAdd for x86_64", .{});10159
9135 //return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand });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);
9136}10302}
913710303
9138fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {10304fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {
...@@ -9471,17 +10637,37 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {...@@ -9471,17 +10637,37 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
9471 switch (int_info.signedness) {10637 switch (int_info.signedness) {
9472 .signed => {10638 .signed => {
9473 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);10639 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);
9474 try self.genShiftBinOpMir(.sal, Type.isize, .{ .register = reg }, .{ .immediate = shift });10640 try self.genShiftBinOpMir(
9475 try self.genShiftBinOpMir(.sar, Type.isize, .{ .register = reg }, .{ .immediate = shift });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 );
9476 },10652 },
9477 .unsigned => {10653 .unsigned => {
9478 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);10654 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);
9479 const mask = (~@as(u64, 0)) >> shift;10655 const mask = (~@as(u64, 0)) >> shift;
9480 if (int_info.bits <= 32) {10656 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 );
9482 } else {10663 } else {
9483 const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask });10664 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 );
9485 }10671 }
9486 },10672 },
9487 }10673 }
...@@ -9508,3 +10694,13 @@ fn regBitSize(self: *Self, ty: Type) u64 {...@@ -9508,3 +10694,13 @@ fn regBitSize(self: *Self, ty: Type) u64 {
9508fn regExtraBits(self: *Self, ty: Type) u64 {10694fn regExtraBits(self: *Self, ty: Type) u64 {
9509 return self.regBitSize(ty) - ty.bitSize(self.target.*);10695 return self.regBitSize(ty) - ty.bitSize(self.target.*);
9510}10696}
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{...@@ -18,142 +18,152 @@ pub const Error = Lower.Error || error{
18};18};
1919
20pub fn emitMir(emit: *Emit) Error!void {20pub fn emitMir(emit: *Emit) Error!void {
21 for (0..emit.lower.mir.instructions.len) |i| {21 for (0..emit.lower.mir.instructions.len) |mir_i| {
22 const index = @intCast(Mir.Inst.Index, i);22 const mir_index = @intCast(Mir.Inst.Index, mir_i);
23 const inst = emit.lower.mir.instructions.get(index);23 try emit.code_offset_mapping.putNoClobber(
2424 emit.lower.allocator,
25 const start_offset = @intCast(u32, emit.code.items.len);25 mir_index,
26 try emit.code_offset_mapping.putNoClobber(emit.lower.allocator, index, start_offset);26 @intCast(u32, emit.code.items.len),
27 for (try emit.lower.lowerMir(inst)) |lower_inst| try lower_inst.encode(emit.code.writer(), .{});27 );
28 const end_offset = @intCast(u32, emit.code.items.len);28 const lowered = try emit.lower.lowerMir(mir_index);
2929 var lowered_relocs = lowered.relocs;
30 switch (inst.tag) {30 for (lowered.insts, 0..) |lowered_inst, lowered_index| {
31 else => {},31 const start_offset = @intCast(u32, emit.code.items.len);
3232 try lowered_inst.encode(emit.code.writer(), .{});
33 .jmp_reloc => try emit.relocs.append(emit.lower.allocator, .{33 const end_offset = @intCast(u32, emit.code.items.len);
34 .source = start_offset,34 while (lowered_relocs.len > 0 and
35 .target = inst.data.inst,35 lowered_relocs[0].lowered_inst_index == lowered_index) : ({
36 .offset = end_offset - 4,36 lowered_relocs = lowered_relocs[1..];
37 .length = 5,37 }) switch (lowered_relocs[0].target) {
38 }),38 .inst => |target| try emit.relocs.append(emit.lower.allocator, .{
3939 .source = start_offset,
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,
48 .target = target,40 .target = target,
49 .offset = end_offset - 4,41 .offset = end_offset - 4,
50 .addend = 0,42 .length = @intCast(u5, end_offset - start_offset),
51 .pcrel = true,43 }),
52 .length = 2,44 .linker_extern_fn => |symbol| if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
53 });45 // Add relocation to the decl.
54 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {46 const atom_index = macho_file.getAtomIndexForSymbol(
55 // Add relocation to the decl.47 .{ .sym_index = symbol.atom_index, .file = null },
56 const atom_index = coff_file.getAtomIndexForSymbol(48 ).?;
57 .{ .sym_index = inst.data.relocation.atom_index, .file = null },49 const target = macho_file.getGlobalByIndex(symbol.sym_index);
58 ).?;50 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
59 const target = coff_file.getGlobalByIndex(inst.data.relocation.sym_index);51 .type = .branch,
60 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{52 .target = target,
61 .type = .direct,53 .offset = end_offset - 4,
62 .target = target,54 .addend = 0,
63 .offset = end_offset - 4,55 .pcrel = true,
64 .addend = 0,56 .length = 2,
65 .pcrel = true,57 });
66 .length = 2,58 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
67 });59 // Add relocation to the decl.
68 } else return emit.fail("TODO implement {} for {}", .{ inst.tag, emit.bin_file.tag }),60 const atom_index = coff_file.getAtomIndexForSymbol(
6961 .{ .sym_index = symbol.atom_index, .file = null },
70 .mov_linker, .lea_linker => if (emit.bin_file.cast(link.File.MachO)) |macho_file| {62 ).?;
71 const metadata =63 const target = coff_file.getGlobalByIndex(symbol.sym_index);
72 emit.lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data;64 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
73 const atom_index = macho_file.getAtomIndexForSymbol(.{65 .type = .direct,
74 .sym_index = metadata.atom_index,66 .target = target,
75 .file = null,67 .offset = end_offset - 4,
76 }).?;68 .addend = 0,
77 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{69 .pcrel = true,
78 .type = switch (inst.ops) {70 .length = 2,
79 .got_reloc => .got,71 });
80 .direct_reloc => .signed,72 } else return emit.fail("TODO implement extern reloc for {s}", .{
81 .tlv_reloc => .tlv,73 @tagName(emit.bin_file.tag),
82 else => unreachable,74 }),
83 },75 .linker_got,
84 .target = .{ .sym_index = metadata.sym_index, .file = null },76 .linker_direct,
85 .offset = @intCast(u32, end_offset - 4),77 .linker_import,
86 .addend = 0,78 .linker_tlv,
87 .pcrel = true,79 => |symbol| if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
88 .length = 2,80 const atom_index = macho_file.getAtomIndexForSymbol(.{
89 });81 .sym_index = symbol.atom_index,
90 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {82 .file = null,
91 const metadata =83 }).?;
92 emit.lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data;84 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
93 const atom_index = coff_file.getAtomIndexForSymbol(.{85 .type = switch (lowered_relocs[0].target) {
94 .sym_index = metadata.atom_index,86 .linker_got => .got,
95 .file = null,87 .linker_direct => .signed,
96 }).?;88 .linker_tlv => .tlv,
97 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{89 else => unreachable,
98 .type = switch (inst.ops) {90 },
99 .got_reloc => .got,91 .target = .{ .sym_index = symbol.sym_index, .file = null },
100 .direct_reloc => .direct,92 .offset = @intCast(u32, end_offset - 4),
101 .import_reloc => .import,93 .addend = 0,
102 else => unreachable,94 .pcrel = true,
103 },95 .length = 2,
104 .target = switch (inst.ops) {96 });
105 .got_reloc,97 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
106 .direct_reloc,98 const atom_index = coff_file.getAtomIndexForSymbol(.{
107 => .{ .sym_index = metadata.sym_index, .file = null },99 .sym_index = symbol.atom_index,
108 .import_reloc => coff_file.getGlobalByIndex(metadata.sym_index),100 .file = null,
109 else => unreachable,101 }).?;
110 },102 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
111 .offset = @intCast(u32, end_offset - 4),103 .type = switch (lowered_relocs[0].target) {
112 .addend = 0,104 .linker_got => .got,
113 .pcrel = true,105 .linker_direct => .direct,
114 .length = 2,106 .linker_import => .import,
115 });107 else => unreachable,
116 } else return emit.fail("TODO implement {} for {}", .{ inst.tag, emit.bin_file.tag }),108 },
117109 .target = switch (lowered_relocs[0].target) {
118 .jcc => try emit.relocs.append(emit.lower.allocator, .{110 .linker_got,
119 .source = start_offset,111 .linker_direct,
120 .target = inst.data.inst_cc.inst,112 => .{ .sym_index = symbol.sym_index, .file = null },
121 .offset = end_offset - 4,113 .linker_import => coff_file.getGlobalByIndex(symbol.sym_index),
122 .length = 6,114 else => unreachable,
123 }),115 },
124116 .offset = @intCast(u32, end_offset - 4),
125 .dbg_line => try emit.dbgAdvancePCAndLine(117 .addend = 0,
126 inst.data.line_column.line,118 .pcrel = true,
127 inst.data.line_column.column,119 .length = 2,
128 ),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 => {128 if (lowered.insts.len == 0) {
131 switch (emit.debug_output) {129 const mir_inst = emit.lower.mir.instructions.get(mir_index);
132 .dwarf => |dw| {130 switch (mir_inst.tag) {
133 try dw.setPrologueEnd();131 else => unreachable,
134 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{132 .pseudo => switch (mir_inst.ops) {
135 emit.prev_di_line, emit.prev_di_column,133 else => unreachable,
136 });134 .pseudo_dbg_prologue_end_none => {
137 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);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 }
138 },146 },
139 .plan9 => {},147 .pseudo_dbg_line_line_column => try emit.dbgAdvancePCAndLine(
140 .none => {},148 mir_inst.data.line_column.line,
141 }149 mir_inst.data.line_column.column,
142 },150 ),
143151 .pseudo_dbg_epilogue_begin_none => {
144 .dbg_epilogue_begin => {152 switch (emit.debug_output) {
145 switch (emit.debug_output) {153 .dwarf => |dw| {
146 .dwarf => |dw| {154 try dw.setEpilogueBegin();
147 try dw.setEpilogueBegin();155 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{
148 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{156 emit.prev_di_line, emit.prev_di_column,
149 emit.prev_di_line, emit.prev_di_column,157 });
150 });158 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
151 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);159 },
160 .plan9 => {},
161 .none => {},
162 }
152 },163 },
153 .plan9 => {},164 .pseudo_dead_none => {},
154 .none => {},165 },
155 }166 }
156 },
157 }167 }
158 }168 }
159 try emit.fixupRelocs();169 try emit.fixupRelocs();
src/arch/x86_64/Encoding.zig+240-107
...@@ -23,6 +23,7 @@ const Data = struct {...@@ -23,6 +23,7 @@ const Data = struct {
23 opc: [7]u8,23 opc: [7]u8,
24 modrm_ext: u3,24 modrm_ext: u3,
25 mode: Mode,25 mode: Mode,
26 feature: Feature,
26};27};
2728
28pub fn findByMnemonic(29pub fn findByMnemonic(
...@@ -57,9 +58,9 @@ pub fn findByMnemonic(...@@ -57,9 +58,9 @@ pub fn findByMnemonic(
57 var shortest_len: ?usize = null;58 var shortest_len: ?usize = null;
58 next: for (mnemonic_to_encodings_map[@enumToInt(mnemonic)]) |data| {59 next: for (mnemonic_to_encodings_map[@enumToInt(mnemonic)]) |data| {
59 switch (data.mode) {60 switch (data.mode) {
60 .rex => if (!rex_required) continue,61 .none, .short => if (rex_required) continue,
61 .long, .sse_long, .sse2_long => {},62 .rex, .rex_short => if (!rex_required) continue,
62 else => if (rex_required) continue,63 else => {},
63 }64 }
64 for (input_ops, data.ops) |input_op, data_op|65 for (input_ops, data.ops) |input_op, data_op|
65 if (!input_op.isSubset(data_op)) continue :next;66 if (!input_op.isSubset(data_op)) continue :next;
...@@ -88,28 +89,13 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct {...@@ -88,28 +89,13 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct {
88 if (modrm_ext) |ext| if (ext != data.modrm_ext) continue;89 if (modrm_ext) |ext| if (ext != data.modrm_ext) continue;
89 if (!std.mem.eql(u8, opc, enc.opcode())) continue;90 if (!std.mem.eql(u8, opc, enc.opcode())) continue;
90 if (prefixes.rex.w) {91 if (prefixes.rex.w) {
91 switch (data.mode) {92 if (!data.mode.isLong()) continue;
92 .short, .fpu, .sse, .sse2, .sse4_1, .none => continue,
93 .long, .sse_long, .sse2_long, .rex => {},
94 }
95 } else if (prefixes.rex.present and !prefixes.rex.isSet()) {93 } else if (prefixes.rex.present and !prefixes.rex.isSet()) {
96 switch (data.mode) {94 if (!data.mode.isRex()) continue;
97 .rex => {},
98 else => continue,
99 }
100 } else if (prefixes.legacy.prefix_66) {95 } else if (prefixes.legacy.prefix_66) {
101 switch (enc.operandBitSize()) {96 if (!data.mode.isShort()) continue;
102 16 => {},
103 else => continue,
104 }
105 } else {97 } else {
106 switch (data.mode) {98 if (data.mode.isShort()) continue;
107 .none => switch (enc.operandBitSize()) {
108 16 => continue,
109 else => {},
110 },
111 else => continue,
112 }
113 }99 }
114 return enc;100 return enc;
115 };101 };
...@@ -130,30 +116,11 @@ pub fn mandatoryPrefix(encoding: *const Encoding) ?u8 {...@@ -130,30 +116,11 @@ pub fn mandatoryPrefix(encoding: *const Encoding) ?u8 {
130116
131pub fn modRmExt(encoding: Encoding) u3 {117pub fn modRmExt(encoding: Encoding) u3 {
132 return switch (encoding.data.op_en) {118 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,
134 else => unreachable,120 else => unreachable,
135 };121 };
136}122}
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
157pub fn format(124pub fn format(
158 encoding: Encoding,125 encoding: Encoding,
159 comptime fmt: []const u8,126 comptime fmt: []const u8,
...@@ -162,14 +129,41 @@ pub fn format(...@@ -162,14 +129,41 @@ pub fn format(
162) !void {129) !void {
163 _ = options;130 _ = options;
164 _ = fmt;131 _ = 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| {133 var opc = encoding.opcode();
171 try writer.print("{x:0>2} ", .{byte});134 if (encoding.data.mode.isVex()) {
172 }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
174 switch (encoding.data.op_en) {168 switch (encoding.data.op_en) {
175 .np, .fd, .td, .i, .zi, .d => {},169 .np, .fd, .td, .i, .zi, .d => {},
...@@ -183,16 +177,17 @@ pub fn format(...@@ -183,16 +177,17 @@ pub fn format(
183 };177 };
184 try writer.print("+{s} ", .{tag});178 try writer.print("+{s} ", .{tag});
185 },179 },
186 .m, .mi, .m1, .mc => try writer.print("/{d} ", .{encoding.modRmExt()}),180 .m, .mi, .m1, .mc, .vmi => try writer.print("/{d} ", .{encoding.modRmExt()}),
187 .mr, .rm, .rmi, .mri, .mrc => try writer.writeAll("/r "),181 .mr, .rm, .rmi, .mri, .mrc, .rvm, .rvmi, .mvr => try writer.writeAll("/r "),
188 }182 }
189183
190 switch (encoding.data.op_en) {184 switch (encoding.data.op_en) {
191 .i, .d, .zi, .oi, .mi, .rmi, .mri => {185 .i, .d, .zi, .oi, .mi, .rmi, .mri, .vmi, .rvmi => {
192 const op = switch (encoding.data.op_en) {186 const op = switch (encoding.data.op_en) {
193 .i, .d => encoding.data.ops[0],187 .i, .d => encoding.data.ops[0],
194 .zi, .oi, .mi => encoding.data.ops[1],188 .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],
196 else => unreachable,191 else => unreachable,
197 };192 };
198 const tag = switch (op) {193 const tag = switch (op) {
...@@ -207,7 +202,7 @@ pub fn format(...@@ -207,7 +202,7 @@ pub fn format(
207 };202 };
208 try writer.print("{s} ", .{tag});203 try writer.print("{s} ", .{tag});
209 },204 },
210 .np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc => {},205 .np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc, .rvm, .mvr => {},
211 }206 }
212207
213 try writer.print("{s} ", .{@tagName(encoding.mnemonic)});208 try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
...@@ -267,44 +262,79 @@ pub const Mnemonic = enum {...@@ -267,44 +262,79 @@ pub const Mnemonic = enum {
267 // MMX262 // MMX
268 movd,263 movd,
269 // SSE264 // SSE
270 addss,265 addps, addss,
271 andps,266 andps,
272 andnps,267 andnps,
273 cmpss,268 cmpss,
274 cvtsi2ss,269 cvtsi2ss,
275 divss,270 divps, divss,
276 maxss, minss,271 maxps, maxss,
277 movaps, movss, movups,272 minps, minss,
278 mulss,273 movaps, movhlps, movss, movups,
274 mulps, mulss,
279 orps,275 orps,
280 pextrw,276 pextrw, pinsrw,
281 pinsrw,277 sqrtps, sqrtss,
282 sqrtps,278 subps, subss,
283 sqrtss,
284 subss,
285 ucomiss,279 ucomiss,
286 xorps,280 xorps,
287 // SSE2281 // SSE2
288 addsd,282 addpd, addsd,
289 andpd,283 andpd,
290 andnpd,284 andnpd,
291 //cmpsd,285 //cmpsd,
292 cvtsd2ss, cvtsi2sd, cvtss2sd,286 cvtsd2ss, cvtsi2sd, cvtss2sd,
293 divsd,287 divpd, divsd,
294 maxsd, minsd,288 maxpd, maxsd,
289 minpd, minsd,
295 movapd,290 movapd,
296 movq, //movd, movsd,291 movq, //movd, movsd,
297 movupd,292 movupd,
298 mulsd,293 mulpd, mulsd,
299 orpd,294 orpd,
300 sqrtpd,295 pshufhw, pshuflw,
301 sqrtsd,296 psrld, psrlq, psrlw,
302 subsd,297 punpckhbw, punpckhdq, punpckhqdq, punpckhwd,
298 punpcklbw, punpckldq, punpcklqdq, punpcklwd,
299 sqrtpd, sqrtsd,
300 subpd, subsd,
303 ucomisd,301 ucomisd,
304 xorpd,302 xorpd,
303 // SSE3
304 movddup, movshdup, movsldup,
305 // SSE4.1305 // SSE4.1
306 roundss,306 pextrb, pextrd, pextrq,
307 roundsd,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,
308 // zig fmt: on338 // zig fmt: on
309};339};
310340
...@@ -317,6 +347,7 @@ pub const OpEn = enum {...@@ -317,6 +347,7 @@ pub const OpEn = enum {
317 fd, td,347 fd, td,
318 m1, mc, mi, mr, rm,348 m1, mc, mi, mr, rm,
319 rmi, mri, mrc,349 rmi, mri, mrc,
350 vmi, rvm, rvmi, mvr,
320 // zig fmt: on351 // zig fmt: on
321};352};
322353
...@@ -331,12 +362,14 @@ pub const Op = enum {...@@ -331,12 +362,14 @@ pub const Op = enum {
331 cl,362 cl,
332 r8, r16, r32, r64,363 r8, r16, r32, r64,
333 rm8, rm16, rm32, rm64,364 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,
335 rel8, rel16, rel32,367 rel8, rel16, rel32,
336 m,368 m,
337 moffs,369 moffs,
338 sreg,370 sreg,
339 xmm, xmm_m32, xmm_m64, xmm_m128,371 xmm, xmm_m32, xmm_m64, xmm_m128,
372 ymm, ymm_m256,
340 // zig fmt: on373 // zig fmt: on
341374
342 pub fn fromOperand(operand: Instruction.Operand) Op {375 pub fn fromOperand(operand: Instruction.Operand) Op {
...@@ -348,6 +381,7 @@ pub const Op = enum {...@@ -348,6 +381,7 @@ pub const Op = enum {
348 .segment => return .sreg,381 .segment => return .sreg,
349 .floating_point => return switch (reg.bitSize()) {382 .floating_point => return switch (reg.bitSize()) {
350 128 => .xmm,383 128 => .xmm,
384 256 => .ymm,
351 else => unreachable,385 else => unreachable,
352 },386 },
353 .general_purpose => {387 .general_purpose => {
...@@ -381,6 +415,7 @@ pub const Op = enum {...@@ -381,6 +415,7 @@ pub const Op = enum {
381 64 => .m64,415 64 => .m64,
382 80 => .m80,416 80 => .m80,
383 128 => .m128,417 128 => .m128,
418 256 => .m256,
384 else => unreachable,419 else => unreachable,
385 };420 };
386 },421 },
...@@ -409,16 +444,52 @@ pub const Op = enum {...@@ -409,16 +444,52 @@ pub const Op = enum {
409 }444 }
410 }445 }
411446
412 pub fn bitSize(op: Op) u64 {447 pub fn immBitSize(op: Op) u64 {
413 return switch (op) {448 return switch (op) {
414 .none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,449 .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,
415 .unity => 1,457 .unity => 1,
416 .imm8, .imm8s, .al, .cl, .r8, .m8, .rm8, .rel8 => 8,458 .imm8, .imm8s, .rel8 => 8,
417 .imm16, .imm16s, .ax, .r16, .m16, .rm16, .rel16 => 16,459 .imm16, .imm16s, .rel16 => 16,
418 .imm32, .imm32s, .eax, .r32, .m32, .rm32, .rel32, .xmm_m32 => 32,460 .imm32, .imm32s, .rel32 => 32,
419 .imm64, .rax, .r64, .m64, .rm64, .xmm_m64 => 64,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,
420 .m80 => 80,490 .m80 => 80,
421 .m128, .xmm, .xmm_m128 => 128,491 .m128, .xmm_m128 => 128,
492 .m256, .ymm_m256 => 256,
422 };493 };
423 }494 }
424495
...@@ -441,7 +512,9 @@ pub const Op = enum {...@@ -441,7 +512,9 @@ pub const Op = enum {
441 .al, .ax, .eax, .rax,512 .al, .ax, .eax, .rax,
442 .r8, .r16, .r32, .r64,513 .r8, .r16, .r32, .r64,
443 .rm8, .rm16, .rm32, .rm64,514 .rm8, .rm16, .rm32, .rm64,
515 .r32_m8, .r32_m16, .r64_m16,
444 .xmm, .xmm_m32, .xmm_m64, .xmm_m128,516 .xmm, .xmm_m32, .xmm_m64, .xmm_m128,
517 .ymm, .ymm_m256,
445 => true,518 => true,
446 else => false,519 else => false,
447 };520 };
...@@ -465,9 +538,11 @@ pub const Op = enum {...@@ -465,9 +538,11 @@ pub const Op = enum {
465 // zig fmt: off538 // zig fmt: off
466 return switch (op) {539 return switch (op) {
467 .rm8, .rm16, .rm32, .rm64,540 .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,
469 .m,543 .m,
470 .xmm_m32, .xmm_m64, .xmm_m128,544 .xmm_m32, .xmm_m64, .xmm_m128,
545 .ymm_m256,
471 => true,546 => true,
472 else => false,547 else => false,
473 };548 };
...@@ -487,15 +562,10 @@ pub const Op = enum {...@@ -487,15 +562,10 @@ pub const Op = enum {
487 .al, .ax, .eax, .rax, .cl => .general_purpose,562 .al, .ax, .eax, .rax, .cl => .general_purpose,
488 .r8, .r16, .r32, .r64 => .general_purpose,563 .r8, .r16, .r32, .r64 => .general_purpose,
489 .rm8, .rm16, .rm32, .rm64 => .general_purpose,564 .rm8, .rm16, .rm32, .rm64 => .general_purpose,
565 .r32_m8, .r32_m16, .r64_m16 => .general_purpose,
490 .sreg => .segment,566 .sreg => .segment,
491 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => .floating_point,567 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => .floating_point,
492 };568 .ymm, .ymm_m256 => .floating_point,
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,
499 };569 };
500 }570 }
501571
...@@ -512,30 +582,27 @@ pub const Op = enum {...@@ -512,30 +582,27 @@ pub const Op = enum {
512 if (op.isRegister() and target.isRegister()) {582 if (op.isRegister() and target.isRegister()) {
513 return switch (target) {583 return switch (target) {
514 .cl, .al, .ax, .eax, .rax => op == target,584 .cl, .al, .ax, .eax, .rax => op == target,
515 else => op.class() == target.class() and switch (target.class()) {585 else => op.class() == target.class() and op.regBitSize() == target.regBitSize(),
516 .floating_point => true,
517 else => op.bitSize() == target.bitSize(),
518 },
519 };586 };
520 }587 }
521 if (op.isMemory() and target.isMemory()) {588 if (op.isMemory() and target.isMemory()) {
522 switch (target) {589 switch (target) {
523 .m => return true,590 .m => return true,
524 else => return op.bitSize() == target.bitSize(),591 else => return op.memBitSize() == target.memBitSize(),
525 }592 }
526 }593 }
527 if (op.isImmediate() and target.isImmediate()) {594 if (op.isImmediate() and target.isImmediate()) {
528 switch (target) {595 switch (target) {
529 .imm64 => if (op.bitSize() <= 64) return true,596 .imm64 => if (op.immBitSize() <= 64) return true,
530 .imm32s, .rel32 => if (op.bitSize() < 32 or (op.bitSize() == 32 and op.isSigned()))597 .imm32s, .rel32 => if (op.immBitSize() < 32 or (op.immBitSize() == 32 and op.isSigned()))
531 return true,598 return true,
532 .imm32 => if (op.bitSize() <= 32) return true,599 .imm32 => if (op.immBitSize() <= 32) return true,
533 .imm16s, .rel16 => if (op.bitSize() < 16 or (op.bitSize() == 16 and op.isSigned()))600 .imm16s, .rel16 => if (op.immBitSize() < 16 or (op.immBitSize() == 16 and op.isSigned()))
534 return true,601 return true,
535 .imm16 => if (op.bitSize() <= 16) return true,602 .imm16 => if (op.immBitSize() <= 16) return true,
536 .imm8s, .rel8 => if (op.bitSize() < 8 or (op.bitSize() == 8 and op.isSigned()))603 .imm8s, .rel8 => if (op.immBitSize() < 8 or (op.immBitSize() == 8 and op.isSigned()))
537 return true,604 return true,
538 .imm8 => if (op.bitSize() <= 8) return true,605 .imm8 => if (op.immBitSize() <= 8) return true,
539 else => {},606 else => {},
540 }607 }
541 return op == target;608 return op == target;
...@@ -547,16 +614,81 @@ pub const Op = enum {...@@ -547,16 +614,81 @@ pub const Op = enum {
547};614};
548615
549pub const Mode = enum {616pub 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 {
550 none,682 none,
551 short,683 avx,
552 fpu,684 avx2,
553 rex,685 f16c,
554 long,686 fma,
555 sse,687 sse,
556 sse_long,
557 sse2,688 sse2,
558 sse2_long,689 sse3,
559 sse4_1,690 sse4_1,
691 x87,
560};692};
561693
562fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Operand) usize {694fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Operand) usize {
...@@ -573,7 +705,7 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op...@@ -573,7 +705,7 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op
573}705}
574706
575const mnemonic_to_encodings_map = init: {707const mnemonic_to_encodings_map = init: {
576 @setEvalBranchQuota(100_000);708 @setEvalBranchQuota(20_000);
577 const encodings = @import("encodings.zig");709 const encodings = @import("encodings.zig");
578 var entries = encodings.table;710 var entries = encodings.table;
579 std.sort.sort(encodings.Entry, &entries, {}, struct {711 std.sort.sort(encodings.Entry, &entries, {}, struct {
...@@ -593,6 +725,7 @@ const mnemonic_to_encodings_map = init: {...@@ -593,6 +725,7 @@ const mnemonic_to_encodings_map = init: {
593 .opc = undefined,725 .opc = undefined,
594 .modrm_ext = entry[4],726 .modrm_ext = entry[4],
595 .mode = entry[5],727 .mode = entry[5],
728 .feature = entry[6],
596 };729 };
597 // TODO: use `@memcpy` for these. When I did that, I got a false positive730 // TODO: use `@memcpy` for these. When I did that, I got a false positive
598 // compile error for this copy happening at compile time.731 // compile error for this copy happening at compile time.
src/arch/x86_64/Lower.zig+283-323
...@@ -5,13 +5,22 @@ mir: Mir,...@@ -5,13 +5,22 @@ mir: Mir,
5target: *const std.Target,5target: *const std.Target,
6err_msg: ?*ErrorMsg = null,6err_msg: ?*ErrorMsg = null,
7src_loc: Module.SrcLoc,7src_loc: Module.SrcLoc,
8result: [8result_insts_len: u8 = undefined,
9result_relocs_len: u8 = undefined,
10result_insts: [
9 std.mem.max(usize, &.{11 std.mem.max(usize, &.{
10 abi.Win64.callee_preserved_regs.len,12 2, // cmovcc: cmovcc \ cmovcc
11 abi.SysV.callee_preserved_regs.len,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
12 })17 })
13]Instruction = undefined,18]Instruction = undefined,
14result_len: usize = undefined,19result_relocs: [
20 std.mem.max(usize, &.{
21 2, // jcc: jcc \ jcc
22 })
23]Reloc = undefined,
1524
16pub const Error = error{25pub const Error = error{
17 OutOfMemory,26 OutOfMemory,
...@@ -20,155 +29,155 @@ pub const Error = error{...@@ -20,155 +29,155 @@ pub const Error = error{
20 CannotEncode,29 CannotEncode,
21};30};
2231
23/// The returned slice is overwritten by the next call to lowerMir.32pub const Reloc = struct {
24pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {33 lowered_inst_index: u8,
25 lower.result = undefined;34 target: Target,
26 errdefer lower.result = undefined;35
27 lower.result_len = 0;36 const Target = union(enum) {
28 defer lower.result_len = undefined;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);
30 switch (inst.tag) {61 switch (inst.tag) {
31 .adc,62 else => try lower.generic(inst),
32 .add,63 .pseudo => switch (inst.ops) {
33 .@"and",64 .pseudo_cmov_z_and_np_rr => {
34 .bsf,65 try lower.emit(.none, .cmovnz, &.{
35 .bsr,66 .{ .reg = inst.data.rr.r2 },
36 .bswap,67 .{ .reg = inst.data.rr.r1 },
37 .bt,68 });
38 .btc,69 try lower.emit(.none, .cmovnp, &.{
39 .btr,70 .{ .reg = inst.data.rr.r1 },
40 .bts,71 .{ .reg = inst.data.rr.r2 },
41 .call,72 });
42 .cbw,73 },
43 .cwde,74 .pseudo_cmov_nz_or_p_rr => {
44 .cdqe,75 try lower.emit(.none, .cmovnz, &.{
45 .cwd,76 .{ .reg = inst.data.rr.r1 },
46 .cdq,77 .{ .reg = inst.data.rr.r2 },
47 .cqo,78 });
48 .cmp,79 try lower.emit(.none, .cmovp, &.{
49 .cmpxchg,80 .{ .reg = inst.data.rr.r1 },
50 .div,81 .{ .reg = inst.data.rr.r2 },
51 .fisttp,82 });
52 .fld,83 },
53 .idiv,84 .pseudo_cmov_nz_or_p_rm_sib,
54 .imul,85 .pseudo_cmov_nz_or_p_rm_rip,
55 .int3,86 => {
56 .jmp,87 try lower.emit(.none, .cmovnz, &.{
57 .lea,88 .{ .reg = inst.data.rx.r1 },
58 .lfence,89 .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
59 .lzcnt,90 });
60 .mfence,91 try lower.emit(.none, .cmovp, &.{
61 .mov,92 .{ .reg = inst.data.rx.r1 },
62 .movbe,93 .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
63 .movd,94 });
64 .movq,95 },
65 .movzx,96 .pseudo_set_z_and_np_r => {
66 .mul,97 try lower.emit(.none, .setz, &.{
67 .neg,98 .{ .reg = inst.data.r_scratch.r1 },
68 .nop,99 });
69 .not,100 try lower.emit(.none, .setnp, &.{
70 .@"or",101 .{ .reg = inst.data.r_scratch.scratch_reg },
71 .pop,102 });
72 .popcnt,103 try lower.emit(.none, .@"and", &.{
73 .push,104 .{ .reg = inst.data.r_scratch.r1 },
74 .rcl,105 .{ .reg = inst.data.r_scratch.scratch_reg },
75 .rcr,106 });
76 .ret,107 },
77 .rol,108 .pseudo_set_z_and_np_m_sib,
78 .ror,109 .pseudo_set_z_and_np_m_rip,
79 .sal,110 => {
80 .sar,111 try lower.emit(.none, .setz, &.{
81 .sbb,112 .{ .mem = lower.mem(inst.ops, inst.data.x_scratch.payload) },
82 .sfence,113 });
83 .shl,114 try lower.emit(.none, .setnp, &.{
84 .shld,115 .{ .reg = inst.data.x_scratch.scratch_reg },
85 .shr,116 });
86 .shrd,117 try lower.emit(.none, .@"and", &.{
87 .sub,118 .{ .mem = lower.mem(inst.ops, inst.data.x_scratch.payload) },
88 .syscall,119 .{ .reg = inst.data.x_scratch.scratch_reg },
89 .@"test",120 });
90 .tzcnt,121 },
91 .ud2,122 .pseudo_set_nz_or_p_r => {
92 .xadd,123 try lower.emit(.none, .setnz, &.{
93 .xchg,124 .{ .reg = inst.data.r_scratch.r1 },
94 .xor,125 });
95126 try lower.emit(.none, .setp, &.{
96 .addss,127 .{ .reg = inst.data.r_scratch.scratch_reg },
97 .andnps,128 });
98 .andps,129 try lower.emit(.none, .@"or", &.{
99 .cmpss,130 .{ .reg = inst.data.r_scratch.r1 },
100 .cvtsi2ss,131 .{ .reg = inst.data.r_scratch.scratch_reg },
101 .divss,132 });
102 .maxss,133 },
103 .minss,134 .pseudo_set_nz_or_p_m_sib,
104 .movaps,135 .pseudo_set_nz_or_p_m_rip,
105 .movss,136 => {
106 .movups,137 try lower.emit(.none, .setnz, &.{
107 .mulss,138 .{ .mem = lower.mem(inst.ops, inst.data.x_scratch.payload) },
108 .orps,139 });
109 .pextrw,140 try lower.emit(.none, .setp, &.{
110 .pinsrw,141 .{ .reg = inst.data.x_scratch.scratch_reg },
111 .roundss,142 });
112 .sqrtps,143 try lower.emit(.none, .@"or", &.{
113 .sqrtss,144 .{ .mem = lower.mem(inst.ops, inst.data.x_scratch.payload) },
114 .subss,145 .{ .reg = inst.data.x_scratch.scratch_reg },
115 .ucomiss,146 });
116 .xorps,147 },
117 .addsd,148 .pseudo_j_z_and_np_inst => {
118 .andnpd,149 try lower.emit(.none, .jnz, &.{
119 .andpd,150 .{ .imm = lower.reloc(.{ .inst = index + 1 }) },
120 .cmpsd,151 });
121 .cvtsd2ss,152 try lower.emit(.none, .jnp, &.{
122 .cvtsi2sd,153 .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) },
123 .cvtss2sd,154 });
124 .divsd,155 },
125 .maxsd,156 .pseudo_j_nz_or_p_inst => {
126 .minsd,157 try lower.emit(.none, .jnz, &.{
127 .movsd,158 .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) },
128 .mulsd,159 });
129 .orpd,160 try lower.emit(.none, .jp, &.{
130 .roundsd,161 .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) },
131 .sqrtpd,162 });
132 .sqrtsd,163 },
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) }}),
160164
161 .push_regs => try lower.mirPushPopRegisterList(inst, .push),165 .pseudo_push_reg_list => try lower.pushPopRegList(.push, inst),
162 .pop_regs => try lower.mirPushPopRegisterList(inst, .pop),166 .pseudo_pop_reg_list => try lower.pushPopRegList(.pop, inst),
163167
164 .dbg_line,168 .pseudo_dbg_prologue_end_none,
165 .dbg_prologue_end,169 .pseudo_dbg_line_line_column,
166 .dbg_epilogue_begin,170 .pseudo_dbg_epilogue_begin_none,
167 .dead,171 .pseudo_dead_none,
168 => {},172 => {},
173 else => unreachable,
174 },
169 }175 }
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 };
172}181}
173182
174pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error {183pub 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 {...@@ -178,12 +187,6 @@ pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error {
178 return error.LowerFail;187 return error.LowerFail;
179}188}
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
187fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {190fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
188 return switch (ops) {191 return switch (ops) {
189 .rri_s,192 .rri_s,
...@@ -191,21 +194,22 @@ fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {...@@ -191,21 +194,22 @@ fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
191 .i_s,194 .i_s,
192 .mi_sib_s,195 .mi_sib_s,
193 .mi_rip_s,196 .mi_rip_s,
194 .lock_mi_sib_s,
195 .lock_mi_rip_s,
196 => Immediate.s(@bitCast(i32, i)),197 => Immediate.s(@bitCast(i32, i)),
197198
199 .rrri,
198 .rri_u,200 .rri_u,
199 .ri_u,201 .ri_u,
200 .i_u,202 .i_u,
201 .mi_sib_u,203 .mi_sib_u,
202 .mi_rip_u,204 .mi_rip_u,
203 .lock_mi_sib_u,
204 .lock_mi_rip_u,
205 .rmi_sib,205 .rmi_sib,
206 .rmi_rip,206 .rmi_rip,
207 .mri_sib,207 .mri_sib,
208 .mri_rip,208 .mri_rip,
209 .rrm_sib,
210 .rrm_rip,
211 .rrmi_sib,
212 .rrmi_rip,
209 => Immediate.u(i),213 => Immediate.u(i),
210214
211 .ri64 => Immediate.u(lower.mir.extraData(Mir.Imm64, i).data.decode()),215 .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 {...@@ -217,76 +221,108 @@ fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
217fn mem(lower: Lower, ops: Mir.Inst.Ops, payload: u32) Memory {221fn mem(lower: Lower, ops: Mir.Inst.Ops, payload: u32) Memory {
218 return lower.mir.resolveFrameLoc(switch (ops) {222 return lower.mir.resolveFrameLoc(switch (ops) {
219 .rm_sib,223 .rm_sib,
220 .rm_sib_cc,
221 .rmi_sib,224 .rmi_sib,
222 .m_sib,225 .m_sib,
223 .m_sib_cc,
224 .mi_sib_u,226 .mi_sib_u,
225 .mi_sib_s,227 .mi_sib_s,
226 .mr_sib,228 .mr_sib,
227 .mrr_sib,229 .mrr_sib,
228 .mri_sib,230 .mri_sib,
229 .lock_m_sib,231 .rrm_sib,
230 .lock_mi_sib_u,232 .rrmi_sib,
231 .lock_mi_sib_s,233
232 .lock_mr_sib,234 .pseudo_cmov_nz_or_p_rm_sib,
235 .pseudo_set_z_and_np_m_sib,
236 .pseudo_set_nz_or_p_m_sib,
233 => lower.mir.extraData(Mir.MemorySib, payload).data.decode(),237 => lower.mir.extraData(Mir.MemorySib, payload).data.decode(),
234238
235 .rm_rip,239 .rm_rip,
236 .rm_rip_cc,
237 .rmi_rip,240 .rmi_rip,
238 .m_rip,241 .m_rip,
239 .m_rip_cc,
240 .mi_rip_u,242 .mi_rip_u,
241 .mi_rip_s,243 .mi_rip_s,
242 .mr_rip,244 .mr_rip,
243 .mrr_rip,245 .mrr_rip,
244 .mri_rip,246 .mri_rip,
245 .lock_m_rip,247 .rrm_rip,
246 .lock_mi_rip_u,248 .rrmi_rip,
247 .lock_mi_rip_s,249
248 .lock_mr_rip,250 .pseudo_cmov_nz_or_p_rm_rip,
251 .pseudo_set_z_and_np_m_rip,
252 .pseudo_set_nz_or_p_m_rip,
249 => lower.mir.extraData(Mir.MemoryRip, payload).data.decode(),253 => lower.mir.extraData(Mir.MemoryRip, payload).data.decode(),
250254
251 .rax_moffs,255 .rax_moffs,
252 .moffs_rax,256 .moffs_rax,
253 .lock_moffs_rax,
254 => lower.mir.extraData(Mir.MemoryMoffs, payload).data.decode(),257 => lower.mir.extraData(Mir.MemoryMoffs, payload).data.decode(),
255258
256 else => unreachable,259 else => unreachable,
257 });260 });
258}261}
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
260fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void {272fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void {
261 lower.result[lower.result_len] = try Instruction.new(prefix, mnemonic, ops);273 lower.result_insts[lower.result_insts_len] = try Instruction.new(prefix, mnemonic, ops);
262 lower.result_len += 1;274 lower.result_insts_len += 1;
263}275}
264276
265fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {277fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
266 try lower.emit(switch (inst.ops) {278 const fixes = switch (inst.ops) {
267 else => .none,279 .none => inst.data.none.fixes,
268 .lock_m_sib,280 .inst => inst.data.inst.fixes,
269 .lock_m_rip,281 .i_s, .i_u => inst.data.i.fixes,
270 .lock_mi_sib_u,282 .r => inst.data.r.fixes,
271 .lock_mi_rip_u,283 .rr => inst.data.rr.fixes,
272 .lock_mi_sib_s,284 .rrr => inst.data.rrr.fixes,
273 .lock_mi_rip_s,285 .rrri => inst.data.rrri.fixes,
274 .lock_mr_sib,286 .rri_s, .rri_u => inst.data.rri.fixes,
275 .lock_mr_rip,287 .ri_s, .ri_u => inst.data.ri.fixes,
276 .lock_moffs_rax,288 .ri64, .rm_sib, .rm_rip, .mr_sib, .mr_rip => inst.data.rx.fixes,
277 => .lock,289 .mrr_sib, .mrr_rip, .rrm_sib, .rrm_rip => inst.data.rrx.fixes,
278 }, switch (inst.tag) {290 .rmi_sib, .rmi_rip, .mri_sib, .mri_rip => inst.data.rix.fixes,
279 inline else => |tag| if (@hasField(Mnemonic, @tagName(tag)))291 .rrmi_sib, .rrmi_rip => inst.data.rrix.fixes,
280 @field(Mnemonic, @tagName(tag))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])
281 else300 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});
283 }, switch (inst.ops) {316 }, switch (inst.ops) {
284 .none => &.{},317 .none => &.{},
318 .inst => &.{
319 .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) },
320 },
285 .i_s, .i_u => &.{321 .i_s, .i_u => &.{
286 .{ .imm = lower.imm(inst.ops, inst.data.i) },322 .{ .imm = lower.imm(inst.ops, inst.data.i.i) },
287 },323 },
288 .r => &.{324 .r => &.{
289 .{ .reg = inst.data.r },325 .{ .reg = inst.data.r.r1 },
290 },326 },
291 .rr => &.{327 .rr => &.{
292 .{ .reg = inst.data.rr.r1 },328 .{ .reg = inst.data.rr.r1 },
...@@ -297,12 +333,18 @@ fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {...@@ -297,12 +333,18 @@ fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {
297 .{ .reg = inst.data.rrr.r2 },333 .{ .reg = inst.data.rrr.r2 },
298 .{ .reg = inst.data.rrr.r3 },334 .{ .reg = inst.data.rrr.r3 },
299 },335 },
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 },
300 .ri_s, .ri_u => &.{342 .ri_s, .ri_u => &.{
301 .{ .reg = inst.data.ri.r },343 .{ .reg = inst.data.ri.r1 },
302 .{ .imm = lower.imm(inst.ops, inst.data.ri.i) },344 .{ .imm = lower.imm(inst.ops, inst.data.ri.i) },
303 },345 },
304 .ri64 => &.{346 .ri64 => &.{
305 .{ .reg = inst.data.rx.r },347 .{ .reg = inst.data.rx.r1 },
306 .{ .imm = lower.imm(inst.ops, inst.data.rx.payload) },348 .{ .imm = lower.imm(inst.ops, inst.data.rx.payload) },
307 },349 },
308 .rri_s, .rri_u => &.{350 .rri_s, .rri_u => &.{
...@@ -310,33 +352,28 @@ fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {...@@ -310,33 +352,28 @@ fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {
310 .{ .reg = inst.data.rri.r2 },352 .{ .reg = inst.data.rri.r2 },
311 .{ .imm = lower.imm(inst.ops, inst.data.rri.i) },353 .{ .imm = lower.imm(inst.ops, inst.data.rri.i) },
312 },354 },
313 .m_sib, .lock_m_sib, .m_rip, .lock_m_rip => &.{355 .m_sib, .m_rip => &.{
314 .{ .mem = lower.mem(inst.ops, inst.data.payload) },356 .{ .mem = lower.mem(inst.ops, inst.data.x.payload) },
315 },357 },
316 .mi_sib_s,358 .mi_sib_s, .mi_sib_u, .mi_rip_u, .mi_rip_s => &.{
317 .lock_mi_sib_s,359 .{ .mem = lower.mem(inst.ops, inst.data.x.payload + 1) },
318 .mi_sib_u,360 .{ .imm = lower.imm(
319 .lock_mi_sib_u,361 inst.ops,
320 .mi_rip_u,362 lower.mir.extraData(Mir.Imm32, inst.data.x.payload).data.imm,
321 .lock_mi_rip_u,363 ) },
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) },
327 },364 },
328 .rm_sib, .rm_rip => &.{365 .rm_sib, .rm_rip => &.{
329 .{ .reg = inst.data.rx.r },366 .{ .reg = inst.data.rx.r1 },
330 .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },367 .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
331 },368 },
332 .rmi_sib, .rmi_rip => &.{369 .rmi_sib, .rmi_rip => &.{
333 .{ .reg = inst.data.rix.r },370 .{ .reg = inst.data.rix.r1 },
334 .{ .mem = lower.mem(inst.ops, inst.data.rix.payload) },371 .{ .mem = lower.mem(inst.ops, inst.data.rix.payload) },
335 .{ .imm = lower.imm(inst.ops, inst.data.rix.i) },372 .{ .imm = lower.imm(inst.ops, inst.data.rix.i) },
336 },373 },
337 .mr_sib, .lock_mr_sib, .mr_rip, .lock_mr_rip => &.{374 .mr_sib, .mr_rip => &.{
338 .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },375 .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
339 .{ .reg = inst.data.rx.r },376 .{ .reg = inst.data.rx.r1 },
340 },377 },
341 .mrr_sib, .mrr_rip => &.{378 .mrr_sib, .mrr_rip => &.{
342 .{ .mem = lower.mem(inst.ops, inst.data.rrx.payload) },379 .{ .mem = lower.mem(inst.ops, inst.data.rrx.payload) },
...@@ -345,137 +382,60 @@ fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {...@@ -345,137 +382,60 @@ fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {
345 },382 },
346 .mri_sib, .mri_rip => &.{383 .mri_sib, .mri_rip => &.{
347 .{ .mem = lower.mem(inst.ops, inst.data.rix.payload) },384 .{ .mem = lower.mem(inst.ops, inst.data.rix.payload) },
348 .{ .reg = inst.data.rix.r },385 .{ .reg = inst.data.rix.r1 },
349 .{ .imm = lower.imm(inst.ops, inst.data.rix.i) },386 .{ .imm = lower.imm(inst.ops, inst.data.rix.i) },
350 },387 },
351 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),388 .rrm_sib, .rrm_rip => &.{
352 });389 .{ .reg = inst.data.rrx.r1 },
353}390 .{ .reg = inst.data.rrx.r2 },
354391 .{ .mem = lower.mem(inst.ops, inst.data.rrx.payload) },
355fn mirString(lower: *Lower, inst: Mir.Inst) Error!void {392 },
356 switch (inst.ops) {393 .rrmi_sib, .rrmi_rip => &.{
357 .string => try lower.emit(switch (inst.data.string.repeat) {394 .{ .reg = inst.data.rrix.r1 },
358 inline else => |repeat| @field(Prefix, @tagName(repeat)),395 .{ .reg = inst.data.rrix.r2 },
359 }, switch (inst.tag) {396 .{ .mem = lower.mem(inst.ops, inst.data.rrix.payload) },
360 inline .cmps, .lods, .movs, .scas, .stos => |tag| switch (inst.data.string.width) {397 .{ .imm = lower.imm(inst.ops, inst.data.rrix.i) },
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) },
373 },398 },
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) {
393 .rax_moffs => &.{399 .rax_moffs => &.{
394 .{ .reg = .rax },400 .{ .reg = .rax },
395 .{ .mem = lower.mem(inst.ops, inst.data.payload) },401 .{ .mem = lower.mem(inst.ops, inst.data.x.payload) },
396 },402 },
397 .moffs_rax, .lock_moffs_rax => &.{403 .moffs_rax => &.{
398 .{ .mem = lower.mem(inst.ops, inst.data.payload) },404 .{ .mem = lower.mem(inst.ops, inst.data.x.payload) },
399 .{ .reg = .rax },405 .{ .reg = .rax },
400 },406 },
401 else => unreachable,407 .extern_fn_reloc => &.{
402 });408 .{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc }) },
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) },
414 },409 },
415 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),410 .got_reloc, .direct_reloc, .import_reloc, .tlv_reloc => ops: {
416 };411 const reg = inst.data.rx.r1;
417 try lower.emit(.none, switch (ops[0].bitSize()) {412 const extra = lower.mir.extraData(Mir.Reloc, inst.data.rx.payload).data;
418 32, 64 => switch (ops[1].bitSize()) {413 _ = lower.reloc(switch (inst.ops) {
419 32 => .movsxd,414 .got_reloc => .{ .linker_got = extra },
420 else => .movsx,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 };
421 },424 },
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 }),
436 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),425 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
437 }426 });
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 }
450}427}
451428
452fn mirPushPopRegisterList(lower: *Lower, inst: Mir.Inst, comptime mnemonic: Mnemonic) Error!void {429fn pushPopRegList(lower: *Lower, comptime mnemonic: Mnemonic, inst: Mir.Inst) Error!void {
453 const reg_list = Mir.RegisterList.fromInt(inst.data.payload);
454 const callee_preserved_regs = abi.getCalleePreservedRegs(lower.target.*);430 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) {
456 .push => .reverse,432 .push => .reverse,
457 .pop => .forward,433 .pop => .forward,
458 else => unreachable,434 else => unreachable,
459 } });435 } });
460 while (it.next()) |i| try lower.emit(.none, mnemonic, &.{.{ .reg = callee_preserved_regs[i] }});436 while (it.next()) |i| try lower.emit(.none, mnemonic, &.{.{
461}437 .reg = callee_preserved_regs[i],
462438 }});
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 });
479}439}
480440
481const abi = @import("abi.zig");441const abi = @import("abi.zig");
src/arch/x86_64/Mir.zig+560-276
...@@ -32,12 +32,260 @@ pub const Inst = struct {...@@ -32,12 +32,260 @@ pub const Inst = struct {
3232
33 pub const Index = u32;33 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
35 pub const Tag = enum(u8) {277 pub const Tag = enum(u8) {
36 /// Add with carry278 /// Add with carry
37 adc,279 adc,
38 /// Add280 /// 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
39 add,285 add,
40 /// Logical and286 /// Logical and
287 /// Bitwise logical and of packed single-precision floating-point values
288 /// Bitwise logical and of packed double-precision floating-point values
41 @"and",289 @"and",
42 /// Bit scan forward290 /// Bit scan forward
43 bsf,291 bsf,
...@@ -46,49 +294,55 @@ pub const Inst = struct {...@@ -46,49 +294,55 @@ pub const Inst = struct {
46 /// Byte swap294 /// Byte swap
47 bswap,295 bswap,
48 /// Bit test296 /// Bit test
49 bt,
50 /// Bit test and complement297 /// Bit test and complement
51 btc,
52 /// Bit test and reset298 /// Bit test and reset
53 btr,
54 /// Bit test and set299 /// Bit test and set
55 bts,300 bt,
56 /// Call301 /// Call
57 call,302 call,
58 /// Convert byte to word303 /// Convert byte to word
59 cbw,304 cbw,
60 /// Convert word to doubleword
61 cwde,
62 /// Convert doubleword to quadword
63 cdqe,
64 /// Convert word to doubleword
65 cwd,
66 /// Convert doubleword to quadword305 /// Convert doubleword to quadword
67 cdq,306 cdq,
68 /// Convert doubleword to quadword307 /// Convert doubleword to quadword
69 cqo,308 cdqe,
309 /// Conditional move
310 cmov,
70 /// Logical compare311 /// Logical compare
312 /// Compare string
313 /// Compare scalar single-precision floating-point values
314 /// Compare scalar double-precision floating-point values
71 cmp,315 cmp,
72 /// Compare and exchange316 /// Compare and exchange
73 cmpxchg,
74 /// Compare and exchange bytes317 /// 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,
76 /// Unsigned division325 /// Unsigned division
77 div,
78 /// Store integer with truncation
79 fisttp,
80 /// Load floating-point value
81 fld,
82 /// Signed division326 /// Signed division
83 idiv,327 /// Divide packed single-precision floating-point values
84 /// Signed multiplication328 /// Divide scalar single-precision floating-point values
85 imul,329 /// Divide packed double-precision floating-point values
330 /// Divide scalar double-precision floating-point values
331 div,
86 ///332 ///
87 int3,333 int3,
334 /// Store integer with truncation
335 istt,
336 /// Conditional jump
337 j,
88 /// Jump338 /// Jump
89 jmp,339 jmp,
340 /// Load floating-point value
341 ld,
90 /// Load effective address342 /// Load effective address
91 lea,343 lea,
344 /// Load string
345 lod,
92 /// Load fence346 /// Load fence
93 lfence,347 lfence,
94 /// Count the number of leading zero bits348 /// Count the number of leading zero bits
...@@ -96,18 +350,24 @@ pub const Inst = struct {...@@ -96,18 +350,24 @@ pub const Inst = struct {
96 /// Memory fence350 /// Memory fence
97 mfence,351 mfence,
98 /// Move352 /// 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
99 mov,358 mov,
100 /// Move data after swapping bytes359 /// Move data after swapping bytes
101 movbe,360 movbe,
102 /// Move doubleword
103 movd,
104 /// Move quadword
105 movq,
106 /// Move with sign extension361 /// Move with sign extension
107 movsx,362 movsx,
108 /// Move with zero extension363 /// Move with zero extension
109 movzx,364 movzx,
110 /// Multiply365 /// 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
111 mul,371 mul,
112 /// Two's complement negation372 /// Two's complement negation
113 neg,373 neg,
...@@ -116,6 +376,8 @@ pub const Inst = struct {...@@ -116,6 +376,8 @@ pub const Inst = struct {
116 /// One's complement negation376 /// One's complement negation
117 not,377 not,
118 /// Logical or378 /// Logical or
379 /// Bitwise logical or of packed single-precision floating-point values
380 /// Bitwise logical or of packed double-precision floating-point values
119 @"or",381 @"or",
120 /// Pop382 /// Pop
121 pop,383 pop,
...@@ -124,33 +386,37 @@ pub const Inst = struct {...@@ -124,33 +386,37 @@ pub const Inst = struct {
124 /// Push386 /// Push
125 push,387 push,
126 /// Rotate left through carry388 /// Rotate left through carry
127 rcl,
128 /// Rotate right through carry389 /// Rotate right through carry
129 rcr,390 rc,
130 /// Return391 /// Return
131 ret,392 ret,
132 /// Rotate left393 /// Rotate left
133 rol,
134 /// Rotate right394 /// Rotate right
135 ror,395 ro,
136 /// Arithmetic shift left396 /// Arithmetic shift left
137 sal,
138 /// Arithmetic shift right397 /// Arithmetic shift right
139 sar,398 sa,
140 /// Integer subtraction with borrow399 /// Integer subtraction with borrow
141 sbb,400 sbb,
401 /// Scan string
402 sca,
403 /// Set byte on condition
404 set,
142 /// Store fence405 /// Store fence
143 sfence,406 sfence,
144 /// Logical shift left407 /// Logical shift left
145 shl,
146 /// Double precision shift left408 /// Double precision shift left
147 shld,
148 /// Logical shift right409 /// Logical shift right
149 shr,
150 /// Double precision shift right410 /// Double precision shift right
151 shrd,411 sh,
152 /// Subtract412 /// 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
153 sub,417 sub,
418 /// Store string
419 sto,
154 /// Syscall420 /// Syscall
155 syscall,421 syscall,
156 /// Test condition422 /// Test condition
...@@ -164,142 +430,131 @@ pub const Inst = struct {...@@ -164,142 +430,131 @@ pub const Inst = struct {
164 /// Exchange register/memory with register430 /// Exchange register/memory with register
165 xchg,431 xchg,
166 /// Logical exclusive-or432 /// 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
167 xor,435 xor,
168436
169 /// Add single precision floating point values437 /// Bitwise logical and not of packed single-precision floating-point values
170 addss,438 /// Bitwise logical and not of packed double-precision floating-point values
171 /// Bitwise logical and of packed single precision floating-point values439 andn,
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,
177 /// Convert doubleword integer to scalar single-precision floating-point value440 /// Convert doubleword integer to scalar single-precision floating-point value
178 cvtsi2ss,441 cvtsi2ss,
179 /// Divide scalar single-precision floating-point values442 /// Maximum of packed single-precision floating-point values
180 divss,443 /// Maximum of scalar single-precision floating-point values
181 /// Return maximum single-precision floating-point value444 /// Maximum of packed double-precision floating-point values
182 maxss,445 /// Maximum of scalar double-precision floating-point values
183 /// Return minimum single-precision floating-point value446 max,
184 minss,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,
185 /// Move aligned packed single-precision floating-point values452 /// Move aligned packed single-precision floating-point values
186 movaps,453 /// Move aligned packed double-precision floating-point values
187 /// Move scalar single-precision floating-point value454 mova,
188 movss,455 /// Move packed single-precision floating-point values high to low
456 movhl,
189 /// Move unaligned packed single-precision floating-point values457 /// Move unaligned packed single-precision floating-point values
190 movups,458 /// Move unaligned packed double-precision floating-point values
191 /// Multiply scalar single-precision floating-point values459 movu,
192 mulss,460 /// Extract byte
193 /// Bitwise logical or of packed single precision floating-point values
194 orps,
195 /// Extract word461 /// Extract word
196 pextrw,462 /// Extract doubleword
463 /// Extract quadword
464 extr,
465 /// Insert byte
197 /// Insert word466 /// Insert word
198 pinsrw,467 /// Insert doubleword
199 /// Round scalar single-precision floating-point values468 /// Insert quadword
200 roundss,469 insr,
201 /// Square root of scalar single precision floating-point value470 /// Square root of packed single-precision floating-point values
202 sqrtps,471 /// Square root of scalar single-precision floating-point value
203 /// Subtract scalar single-precision floating-point values472 /// Square root of packed double-precision floating-point values
204 sqrtss,473 /// Square root of scalar double-precision floating-point value
205 /// Square root of single precision floating-point values474 sqrt,
206 subss,
207 /// Unordered compare scalar single-precision floating-point values475 /// Unordered compare scalar single-precision floating-point values
208 ucomiss,476 /// Unordered compare scalar double-precision floating-point values
209 /// Bitwise logical xor of packed single precision floating-point values477 ucomi,
210 xorps,478 /// Unpack and interleave high packed single-precision floating-point values
211 /// Add double precision floating point values479 /// Unpack and interleave high packed double-precision floating-point values
212 addsd,480 unpckh,
213 /// Bitwise logical and not of packed double precision floating-point values481 /// Unpack and interleave low packed single-precision floating-point values
214 andnpd,482 /// Unpack and interleave low packed double-precision floating-point values
215 /// Bitwise logical and of packed double precision floating-point values483 unpckl,
216 andpd,484
217 /// Compare scalar double-precision floating-point values
218 cmpsd,
219 /// Convert scalar double-precision floating-point value to scalar single-precision floating-point value485 /// Convert scalar double-precision floating-point value to scalar single-precision floating-point value
220 cvtsd2ss,486 cvtsd2ss,
221 /// Convert doubleword integer to scalar double-precision floating-point value487 /// Convert doubleword integer to scalar double-precision floating-point value
222 cvtsi2sd,488 cvtsi2sd,
223 /// Convert scalar single-precision floating-point value to scalar double-precision floating-point value489 /// Convert scalar single-precision floating-point value to scalar double-precision floating-point value
224 cvtss2sd,490 cvtss2sd,
225 /// Divide scalar double-precision floating-point values491 /// Shuffle packed high words
226 divsd,492 shufh,
227 /// Return maximum double-precision floating-point value493 /// Shuffle packed low words
228 maxsd,494 shufl,
229 /// Return minimum double-precision floating-point value495 /// Shift packed data right logical
230 minsd,496 /// Shift packed data right logical
231 /// Move scalar double-precision floating-point value497 /// Shift packed data right logical
232 movsd,498 srl,
233 /// Multiply scalar double-precision floating-point values499 /// Unpack high data
234 mulsd,500 unpckhbw,
235 /// Bitwise logical or of packed double precision floating-point values501 /// Unpack high data
236 orpd,502 unpckhdq,
237 /// Round scalar double-precision floating-point values503 /// Unpack high data
238 roundsd,504 unpckhqdq,
239 /// Square root of double precision floating-point values505 /// Unpack high data
240 sqrtpd,506 unpckhwd,
241 /// Square root of scalar double precision floating-point value507 /// Unpack low data
242 sqrtsd,508 unpcklbw,
243 /// Subtract scalar double-precision floating-point values509 /// Unpack low data
244 subsd,510 unpckldq,
245 /// Unordered compare scalar double-precision floating-point values511 /// Unpack low data
246 ucomisd,512 unpcklqdq,
247 /// Bitwise logical xor of packed double precision floating-point values513 /// Unpack low data
248 xorpd,514 unpcklwd,
249515
250 /// Compare string operands516 /// Replicate double floating-point values
251 cmps,517 movddup,
252 /// Load string518 /// Replicate single floating-point values
253 lods,519 movshdup,
254 /// Move data from string to string520 /// Replicate single floating-point values
255 movs,521 movsldup,
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,
274522
275 /// Call to an extern symbol via linker relocation.523 /// Round packed single-precision floating-point values
276 /// Uses `relocation` payload.524 /// Round scalar single-precision floating-point value
277 call_extern,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.529 /// Convert 16-bit floating-point values to single-precision floating-point values
280 lea_linker,530 cvtph2ps,
281 /// Move address of a symbol not yet allocated in VM.531 /// Convert single-precision floating-point values to 16-bit floating-point values
282 mov_linker,532 cvtps2ph,
283533
284 /// End of prologue534 /// Fused multiply-add of packed single-precision floating-point values
285 dbg_prologue_end,535 /// Fused multiply-add of scalar single-precision floating-point values
286 /// Start of epilogue536 /// Fused multiply-add of packed double-precision floating-point values
287 dbg_epilogue_begin,537 /// Fused multiply-add of scalar double-precision floating-point values
288 /// Update debug line538 fmadd132,
289 /// Uses `line_column` payload containing the line and column.539 /// Fused multiply-add of packed single-precision floating-point values
290 dbg_line,540 /// Fused multiply-add of scalar single-precision floating-point values
291 /// Push registers541 /// Fused multiply-add of packed double-precision floating-point values
292 /// Uses `payload` payload containing `RegisterList.asInt` directly.542 /// Fused multiply-add of scalar double-precision floating-point values
293 push_regs,543 fmadd213,
294 /// Pop registers544 /// Fused multiply-add of packed single-precision floating-point values
295 /// Uses `payload` payload containing `RegisterList.asInt` directly.545 /// Fused multiply-add of scalar single-precision floating-point values
296 pop_regs,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 /// Tombstone550 /// A pseudo instruction that requires special lowering.
299 /// Emitter should skip this instruction.551 /// This should be the only tag in this enum that doesn't
300 dead,552 /// directly correspond to one or more instruction mnemonics.
553 pseudo,
301 };554 };
302555
556 pub const FixedTag = struct { Fixes, Tag };
557
303 pub const Ops = enum(u8) {558 pub const Ops = enum(u8) {
304 /// No data associated with this instruction (only mnemonic is used).559 /// No data associated with this instruction (only mnemonic is used).
305 none,560 none,
...@@ -312,18 +567,15 @@ pub const Inst = struct {...@@ -312,18 +567,15 @@ pub const Inst = struct {
312 /// Register, register, register operands.567 /// Register, register, register operands.
313 /// Uses `rrr` payload.568 /// Uses `rrr` payload.
314 rrr,569 rrr,
570 /// Register, register, register, immediate (byte) operands.
571 /// Uses `rrri` payload.
572 rrri,
315 /// Register, register, immediate (sign-extended) operands.573 /// Register, register, immediate (sign-extended) operands.
316 /// Uses `rri` payload.574 /// Uses `rri` payload.
317 rri_s,575 rri_s,
318 /// Register, register, immediate (unsigned) operands.576 /// Register, register, immediate (unsigned) operands.
319 /// Uses `rri` payload.577 /// Uses `rri` payload.
320 rri_u,578 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,
327 /// Register, immediate (sign-extended) operands.579 /// Register, immediate (sign-extended) operands.
328 /// Uses `ri` payload.580 /// Uses `ri` payload.
329 ri_s,581 ri_s,
...@@ -348,41 +600,41 @@ pub const Inst = struct {...@@ -348,41 +600,41 @@ pub const Inst = struct {
348 /// Register, memory (RIP) operands.600 /// Register, memory (RIP) operands.
349 /// Uses `rx` payload.601 /// Uses `rx` payload.
350 rm_rip,602 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,
357 /// Register, memory (SIB), immediate (byte) operands.603 /// Register, memory (SIB), immediate (byte) operands.
358 /// Uses `rix` payload with extra data of type `MemorySib`.604 /// Uses `rix` payload with extra data of type `MemorySib`.
359 rmi_sib,605 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,
360 /// Register, memory (RIP), immediate (byte) operands.618 /// Register, memory (RIP), immediate (byte) operands.
361 /// Uses `rix` payload with extra data of type `MemoryRip`.619 /// Uses `rix` payload with extra data of type `MemoryRip`.
362 rmi_rip,620 rmi_rip,
363 /// Single memory (SIB) operand.621 /// Single memory (SIB) operand.
364 /// Uses `payload` with extra data of type `MemorySib`.622 /// Uses `x` with extra data of type `MemorySib`.
365 m_sib,623 m_sib,
366 /// Single memory (RIP) operand.624 /// Single memory (RIP) operand.
367 /// Uses `payload` with extra data of type `MemoryRip`.625 /// Uses `x` with extra data of type `MemoryRip`.
368 m_rip,626 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,
375 /// Memory (SIB), immediate (unsigned) operands.627 /// 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`.
377 mi_sib_u,629 mi_sib_u,
378 /// Memory (RIP), immediate (unsigned) operands.630 /// 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`.
380 mi_rip_u,632 mi_rip_u,
381 /// Memory (SIB), immediate (sign-extend) operands.633 /// 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`.
383 mi_sib_s,635 mi_sib_s,
384 /// Memory (RIP), immediate (sign-extend) operands.636 /// 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`.
386 mi_rip_s,638 mi_rip_s,
387 /// Memory (SIB), register operands.639 /// Memory (SIB), register operands.
388 /// Uses `rx` payload with extra data of type `MemorySib`.640 /// Uses `rx` payload with extra data of type `MemorySib`.
...@@ -403,161 +655,200 @@ pub const Inst = struct {...@@ -403,161 +655,200 @@ pub const Inst = struct {
403 /// Uses `rix` payload with extra data of type `MemoryRip`.655 /// Uses `rix` payload with extra data of type `MemoryRip`.
404 mri_rip,656 mri_rip,
405 /// Rax, Memory moffs.657 /// Rax, Memory moffs.
406 /// Uses `payload` with extra data of type `MemoryMoffs`.658 /// Uses `x` with extra data of type `MemoryMoffs`.
407 rax_moffs,659 rax_moffs,
408 /// Memory moffs, rax.660 /// Memory moffs, rax.
409 /// Uses `payload` with extra data of type `MemoryMoffs`.661 /// Uses `x` with extra data of type `MemoryMoffs`.
410 moffs_rax,662 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,
438 /// References another Mir instruction directly.663 /// References another Mir instruction directly.
439 /// Uses `inst` payload.664 /// Uses `inst` payload.
440 inst,665 inst,
441 /// References another Mir instruction directly with condition code (CC).666 /// Linker relocation - external function.
442 /// Uses `inst_cc` payload.
443 inst_cc,
444 /// String repeat and width
445 /// Uses `string` payload.
446 string,
447 /// Uses `reloc` payload.667 /// Uses `reloc` payload.
448 reloc,668 extern_fn_reloc,
449 /// Linker relocation - GOT indirection.669 /// Linker relocation - GOT indirection.
450 /// Uses `payload` payload with extra data of type `LeaRegisterReloc`.670 /// Uses `rx` payload with extra data of type `Reloc`.
451 got_reloc,671 got_reloc,
452 /// Linker relocation - direct reference.672 /// Linker relocation - direct reference.
453 /// Uses `payload` payload with extra data of type `LeaRegisterReloc`.673 /// Uses `rx` payload with extra data of type `Reloc`.
454 direct_reloc,674 direct_reloc,
455 /// Linker relocation - imports table indirection (binding).675 /// 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`.
457 import_reloc,677 import_reloc,
458 /// Linker relocation - threadlocal variable via GOT indirection.678 /// 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`.
460 tlv_reloc,680 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,
461 };746 };
462747
463 pub const Data = union {748 pub const Data = union {
749 none: struct {
750 fixes: Fixes = ._,
751 },
464 /// References another Mir instruction.752 /// References another Mir instruction.
465 inst: Index,753 inst: struct {
466 /// Another instruction with condition code (CC).754 fixes: Fixes = ._,
467 /// Used by `jcc`.
468 inst_cc: struct {
469 /// Another instruction.
470 inst: Index,755 inst: Index,
471 /// A condition code for use with EFLAGS register.
472 cc: bits.Condition,
473 },756 },
474 /// A 32-bit immediate value.757 /// A 32-bit immediate value.
475 i: u32,758 i: struct {
476 r: Register,759 fixes: Fixes = ._,
760 i: u32,
761 },
762 r: struct {
763 fixes: Fixes = ._,
764 r1: Register,
765 },
477 rr: struct {766 rr: struct {
767 fixes: Fixes = ._,
478 r1: Register,768 r1: Register,
479 r2: Register,769 r2: Register,
480 },770 },
481 rrr: struct {771 rrr: struct {
772 fixes: Fixes = ._,
482 r1: Register,773 r1: Register,
483 r2: Register,774 r2: Register,
484 r3: Register,775 r3: Register,
485 },776 },
486 rri: struct {777 rrri: struct {
778 fixes: Fixes = ._,
487 r1: Register,779 r1: Register,
488 r2: Register,780 r2: Register,
489 i: u32,781 r3: Register,
490 },782 i: u8,
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,
500 },783 },
501 /// Register, register with condition code (CC).784 rri: struct {
502 rr_cc: struct {785 fixes: Fixes = ._,
503 r1: Register,786 r1: Register,
504 r2: Register,787 r2: Register,
505 cc: bits.Condition,788 i: u32,
506 },789 },
507 /// Register, immediate.790 /// Register, immediate.
508 ri: struct {791 ri: struct {
509 r: Register,792 fixes: Fixes = ._,
793 r1: Register,
510 i: u32,794 i: u32,
511 },795 },
512 /// Register, followed by custom payload found in extra.796 /// Register, followed by custom payload found in extra.
513 rx: struct {797 rx: struct {
514 r: Register,798 fixes: Fixes = ._,
515 payload: u32,799 r1: Register,
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,
526 payload: u32,800 payload: u32,
527 },801 },
528 /// Register, register, followed by Custom payload found in extra.802 /// Register, register, followed by Custom payload found in extra.
529 rrx: struct {803 rrx: struct {
804 fixes: Fixes = ._,
530 r1: Register,805 r1: Register,
531 r2: Register,806 r2: Register,
532 payload: u32,807 payload: u32,
533 },808 },
534 /// Register, byte immediate, followed by Custom payload found in extra.809 /// Register, byte immediate, followed by Custom payload found in extra.
535 rix: struct {810 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,
537 i: u8,821 i: u8,
538 payload: u32,822 payload: u32,
539 },823 },
540 /// String instruction prefix and width.824 /// Register, scratch register
541 string: struct {825 r_scratch: struct {
542 repeat: bits.StringRepeat,826 fixes: Fixes = ._,
543 width: bits.StringWidth,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,
544 },840 },
545 /// Relocation for the linker where:841 /// Relocation for the linker where:
546 /// * `atom_index` is the index of the source842 /// * `atom_index` is the index of the source
547 /// * `sym_index` is the index of the target843 /// * `sym_index` is the index of the target
548 relocation: struct {844 reloc: Reloc,
549 /// Index of the containing atom.
550 atom_index: u32,
551 /// Index into the linker's symbol table.
552 sym_index: u32,
553 },
554 /// Debug line and column position845 /// Debug line and column position
555 line_column: struct {846 line_column: struct {
556 line: u32,847 line: u32,
557 column: u32,848 column: u32,
558 },849 },
559 /// Index into `extra`. Meaning of what can be found there is context-dependent.850 /// Register list
560 payload: u32,851 reg_list: RegisterList,
561 };852 };
562853
563 // Make sure we don't accidentally make instructions bigger than expected.854 // Make sure we don't accidentally make instructions bigger than expected.
...@@ -569,9 +860,8 @@ pub const Inst = struct {...@@ -569,9 +860,8 @@ pub const Inst = struct {
569 }860 }
570};861};
571862
572pub const LeaRegisterReloc = struct {863/// A linker symbol not yet allocated in VM.
573 /// Destination register.864pub const Reloc = struct {
574 reg: u32,
575 /// Index of the containing atom.865 /// Index of the containing atom.
576 atom_index: u32,866 atom_index: u32,
577 /// Index into the linker's symbol table.867 /// Index into the linker's symbol table.
...@@ -606,21 +896,15 @@ pub const RegisterList = struct {...@@ -606,21 +896,15 @@ pub const RegisterList = struct {
606 return self.bitset.iterator(options);896 return self.bitset.iterator(options);
607 }897 }
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
619 pub fn count(self: Self) u32 {899 pub fn count(self: Self) u32 {
620 return @intCast(u32, self.bitset.count());900 return @intCast(u32, self.bitset.count());
621 }901 }
622};902};
623903
904pub const Imm32 = struct {
905 imm: u32,
906};
907
624pub const Imm64 = struct {908pub const Imm64 = struct {
625 msb: u32,909 msb: u32,
626 lsb: u32,910 lsb: u32,
src/arch/x86_64/bits.zig+21-7
...@@ -6,9 +6,6 @@ const Allocator = std.mem.Allocator;...@@ -6,9 +6,6 @@ const Allocator = std.mem.Allocator;
6const ArrayList = std.ArrayList;6const ArrayList = std.ArrayList;
7const DW = std.dwarf;7const 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
12/// EFLAGS condition codes9/// EFLAGS condition codes
13pub const Condition = enum(u5) {10pub const Condition = enum(u5) {
14 /// above11 /// above
...@@ -72,6 +69,12 @@ pub const Condition = enum(u5) {...@@ -72,6 +69,12 @@ pub const Condition = enum(u5) {
72 /// zero69 /// zero
73 z,70 z,
7471
72 // Pseudo conditions
73 /// zero and not parity
74 z_and_np,
75 /// not zero or parity
76 nz_or_p,
77
75 /// Converts a std.math.CompareOperator into a condition flag,78 /// Converts a std.math.CompareOperator into a condition flag,
76 /// i.e. returns the condition that is true iff the result of the79 /// i.e. returns the condition that is true iff the result of the
77 /// comparison is true. Assumes signed comparison80 /// comparison is true. Assumes signed comparison
...@@ -143,6 +146,9 @@ pub const Condition = enum(u5) {...@@ -143,6 +146,9 @@ pub const Condition = enum(u5) {
143 .po => .pe,146 .po => .pe,
144 .s => .ns,147 .s => .ns,
145 .z => .nz,148 .z => .nz,
149
150 .z_and_np => .nz_or_p,
151 .nz_or_p => .z_and_np,
146 };152 };
147 }153 }
148};154};
...@@ -476,7 +482,9 @@ pub const Memory = union(enum) {...@@ -476,7 +482,9 @@ pub const Memory = union(enum) {
476 dword,482 dword,
477 qword,483 qword,
478 tbyte,484 tbyte,
479 dqword,485 xword,
486 yword,
487 zword,
480488
481 pub fn fromSize(size: u32) PtrSize {489 pub fn fromSize(size: u32) PtrSize {
482 return switch (size) {490 return switch (size) {
...@@ -484,7 +492,9 @@ pub const Memory = union(enum) {...@@ -484,7 +492,9 @@ pub const Memory = union(enum) {
484 2...2 => .word,492 2...2 => .word,
485 3...4 => .dword,493 3...4 => .dword,
486 5...8 => .qword,494 5...8 => .qword,
487 9...16 => .dqword,495 9...16 => .xword,
496 17...32 => .yword,
497 33...64 => .zword,
488 else => unreachable,498 else => unreachable,
489 };499 };
490 }500 }
...@@ -496,7 +506,9 @@ pub const Memory = union(enum) {...@@ -496,7 +506,9 @@ pub const Memory = union(enum) {
496 32 => .dword,506 32 => .dword,
497 64 => .qword,507 64 => .qword,
498 80 => .tbyte,508 80 => .tbyte,
499 128 => .dqword,509 128 => .xword,
510 256 => .yword,
511 512 => .zword,
500 else => unreachable,512 else => unreachable,
501 };513 };
502 }514 }
...@@ -508,7 +520,9 @@ pub const Memory = union(enum) {...@@ -508,7 +520,9 @@ pub const Memory = union(enum) {
508 .dword => 32,520 .dword => 32,
509 .qword => 64,521 .qword => 64,
510 .tbyte => 80,522 .tbyte => 80,
511 .dqword => 128,523 .xword => 128,
524 .yword => 256,
525 .zword => 512,
512 };526 };
513 }527 }
514 };528 };
src/arch/x86_64/encoder.zig+154-35
...@@ -151,15 +151,12 @@ pub const Instruction = struct {...@@ -151,15 +151,12 @@ pub const Instruction = struct {
151 moffs.offset,151 moffs.offset,
152 }),152 }),
153 },153 },
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())}),
155 }155 }
156 }156 }
157157
158 pub fn fmtPrint(op: Operand, enc_op: Encoding.Op) std.fmt.Formatter(fmt) {158 pub fn fmtPrint(op: Operand, enc_op: Encoding.Op) std.fmt.Formatter(fmt) {
159 return .{ .data = .{159 return .{ .data = .{ .op = op, .enc_op = enc_op } };
160 .op = op,
161 .enc_op = enc_op,
162 } };
163 }160 }
164 };161 };
165162
...@@ -209,10 +206,16 @@ pub const Instruction = struct {...@@ -209,10 +206,16 @@ pub const Instruction = struct {
209 const enc = inst.encoding;206 const enc = inst.encoding;
210 const data = enc.data;207 const data = enc.data;
211208
212 try inst.encodeLegacyPrefixes(encoder);209 if (data.mode.isVex()) {
213 try inst.encodeMandatoryPrefix(encoder);210 try inst.encodeVexPrefix(encoder);
214 try inst.encodeRexPrefix(encoder);211 const opc = inst.encoding.opcode();
215 try inst.encodeOpcode(encoder);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
217 switch (data.op_en) {220 switch (data.op_en) {
218 .np, .o => {},221 .np, .o => {},
...@@ -222,25 +225,28 @@ pub const Instruction = struct {...@@ -222,25 +225,28 @@ pub const Instruction = struct {
222 .td => try encoder.imm64(inst.ops[0].mem.moffs.offset),225 .td => try encoder.imm64(inst.ops[0].mem.moffs.offset),
223 else => {226 else => {
224 const mem_op = switch (data.op_en) {227 const mem_op = switch (data.op_en) {
225 .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.ops[0],228 .m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0],
226 .rm, .rmi => inst.ops[1],229 .rm, .rmi, .vmi => inst.ops[1],
230 .rvm, .rvmi => inst.ops[2],
227 else => unreachable,231 else => unreachable,
228 };232 };
229 switch (mem_op) {233 switch (mem_op) {
230 .reg => |reg| {234 .reg => |reg| {
231 const rm = switch (data.op_en) {235 const rm = switch (data.op_en) {
232 .m, .mi, .m1, .mc => enc.modRmExt(),236 .m, .mi, .m1, .mc, .vmi => enc.modRmExt(),
233 .mr, .mri, .mrc => inst.ops[1].reg.lowEnc(),237 .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(),
235 else => unreachable,240 else => unreachable,
236 };241 };
237 try encoder.modRm_direct(rm, reg.lowEnc());242 try encoder.modRm_direct(rm, reg.lowEnc());
238 },243 },
239 .mem => |mem| {244 .mem => |mem| {
240 const op = switch (data.op_en) {245 const op = switch (data.op_en) {
241 .m, .mi, .m1, .mc => .none,246 .m, .mi, .m1, .mc, .vmi => .none,
242 .mr, .mri, .mrc => inst.ops[1],247 .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],
244 else => unreachable,250 else => unreachable,
245 };251 };
246 try encodeMemory(enc, mem, op, encoder);252 try encodeMemory(enc, mem, op, encoder);
...@@ -250,7 +256,8 @@ pub const Instruction = struct {...@@ -250,7 +256,8 @@ pub const Instruction = struct {
250256
251 switch (data.op_en) {257 switch (data.op_en) {
252 .mi => try encodeImm(inst.ops[1].imm, data.ops[1], encoder),258 .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),
254 else => {},261 else => {},
255 }262 }
256 },263 },
...@@ -282,11 +289,9 @@ pub const Instruction = struct {...@@ -282,11 +289,9 @@ pub const Instruction = struct {
282 .rep, .repe, .repz => legacy.prefix_f3 = true,289 .rep, .repe, .repz => legacy.prefix_f3 = true,
283 }290 }
284291
285 if (data.mode == .none) {292 switch (data.mode) {
286 const bit_size = enc.operandBitSize();293 .short, .rex_short => legacy.set16BitOverride(),
287 if (bit_size == 16) {294 else => {},
288 legacy.set16BitOverride();
289 }
290 }295 }
291296
292 const segment_override: ?Register = switch (op_en) {297 const segment_override: ?Register = switch (op_en) {
...@@ -309,6 +314,7 @@ pub const Instruction = struct {...@@ -309,6 +314,7 @@ pub const Instruction = struct {
309 }314 }
310 else315 else
311 null,316 null,
317 .vmi, .rvm, .rvmi, .mvr => unreachable,
312 };318 };
313 if (segment_override) |seg| {319 if (segment_override) |seg| {
314 legacy.setSegmentOverride(seg);320 legacy.setSegmentOverride(seg);
...@@ -322,10 +328,7 @@ pub const Instruction = struct {...@@ -322,10 +328,7 @@ pub const Instruction = struct {
322328
323 var rex = Rex{};329 var rex = Rex{};
324 rex.present = inst.encoding.data.mode == .rex;330 rex.present = inst.encoding.data.mode == .rex;
325 switch (inst.encoding.data.mode) {331 rex.w = inst.encoding.data.mode == .long;
326 .long, .sse_long, .sse2_long => rex.w = true,
327 else => {},
328 }
329332
330 switch (op_en) {333 switch (op_en) {
331 .np, .i, .zi, .fd, .td, .d => {},334 .np, .i, .zi, .fd, .td, .d => {},
...@@ -346,11 +349,71 @@ pub const Instruction = struct {...@@ -346,11 +349,71 @@ pub const Instruction = struct {
346 rex.b = b_x_op.isBaseExtended();349 rex.b = b_x_op.isBaseExtended();
347 rex.x = b_x_op.isIndexExtended();350 rex.x = b_x_op.isIndexExtended();
348 },351 },
352 .vmi, .rvm, .rvmi, .mvr => unreachable,
349 }353 }
350354
351 try encoder.rex(rex);355 try encoder.rex(rex);
352 }356 }
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
354 fn encodeMandatoryPrefix(inst: Instruction, encoder: anytype) !void {417 fn encodeMandatoryPrefix(inst: Instruction, encoder: anytype) !void {
355 const prefix = inst.encoding.mandatoryPrefix() orelse return;418 const prefix = inst.encoding.mandatoryPrefix() orelse return;
356 try encoder.opcode_1byte(prefix);419 try encoder.opcode_1byte(prefix);
...@@ -443,8 +506,8 @@ pub const Instruction = struct {...@@ -443,8 +506,8 @@ pub const Instruction = struct {
443 }506 }
444507
445 fn encodeImm(imm: Immediate, kind: Encoding.Op, encoder: anytype) !void {508 fn encodeImm(imm: Immediate, kind: Encoding.Op, encoder: anytype) !void {
446 const raw = imm.asUnsigned(kind.bitSize());509 const raw = imm.asUnsigned(kind.immBitSize());
447 switch (kind.bitSize()) {510 switch (kind.immBitSize()) {
448 8 => try encoder.imm8(@intCast(u8, raw)),511 8 => try encoder.imm8(@intCast(u8, raw)),
449 16 => try encoder.imm16(@intCast(u16, raw)),512 16 => try encoder.imm16(@intCast(u16, raw)),
450 32 => try encoder.imm32(@intCast(u32, raw)),513 32 => try encoder.imm32(@intCast(u32, raw)),
...@@ -562,17 +625,48 @@ fn Encoder(comptime T: type, comptime opts: Options) type {...@@ -562,17 +625,48 @@ fn Encoder(comptime T: type, comptime opts: Options) type {
562 /// or one of reg, index, r/m, base, or opcode-reg might be extended.625 /// or one of reg, index, r/m, base, or opcode-reg might be extended.
563 ///626 ///
564 /// See struct `Rex` for a description of each field.627 /// See struct `Rex` for a description of each field.
565 pub fn rex(self: Self, byte: Rex) !void {628 pub fn rex(self: Self, fields: Rex) !void {
566 if (!byte.present and !byte.isSet()) return;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;633 if (fields.w) byte |= 0b1000;
571 if (byte.r) value |= 0b0100;634 if (fields.r) byte |= 0b0100;
572 if (byte.x) value |= 0b0010;635 if (fields.x) byte |= 0b0010;
573 if (byte.b) value |= 0b0001;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 }
576 }670 }
577671
578 // ------672 // ------
...@@ -848,6 +942,31 @@ pub const Rex = struct {...@@ -848,6 +942,31 @@ pub const Rex = struct {
848 }942 }
849};943};
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
851// Tests970// Tests
852fn expectEqualHexStrings(expected: []const u8, given: []const u8, assembly: []const u8) !void {971fn expectEqualHexStrings(expected: []const u8, given: []const u8, assembly: []const u8) !void {
853 assert(expected.len > 0);972 assert(expected.len > 0);
src/arch/x86_64/encodings.zig+1156-870
...@@ -3,933 +3,1219 @@ const Mnemonic = Encoding.Mnemonic;...@@ -3,933 +3,1219 @@ const Mnemonic = Encoding.Mnemonic;
3const OpEn = Encoding.OpEn;3const OpEn = Encoding.OpEn;
4const Op = Encoding.Op;4const Op = Encoding.Op;
5const Mode = Encoding.Mode;5const Mode = Encoding.Mode;
6const Feature = Encoding.Feature;
67
7const modrm_ext = u3;8const 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
11// TODO move this into a .zon file when Zig is capable of importing .zon files12// TODO move this into a .zon file when Zig is capable of importing .zon files
12// zig fmt: off13// zig fmt: off
13pub const table = [_]Entry{14pub const table = [_]Entry{
14 // General-purpose15 // General-purpose
15 .{ .adc, .zi, &.{ .al, .imm8 }, &.{ 0x14 }, 0, .none },16 .{ .adc, .zi, &.{ .al, .imm8 }, &.{ 0x14 }, 0, .none, .none },
16 .{ .adc, .zi, &.{ .ax, .imm16 }, &.{ 0x15 }, 0, .none },17 .{ .adc, .zi, &.{ .ax, .imm16 }, &.{ 0x15 }, 0, .short, .none },
17 .{ .adc, .zi, &.{ .eax, .imm32 }, &.{ 0x15 }, 0, .none },18 .{ .adc, .zi, &.{ .eax, .imm32 }, &.{ 0x15 }, 0, .none, .none },
18 .{ .adc, .zi, &.{ .rax, .imm32s }, &.{ 0x15 }, 0, .long },19 .{ .adc, .zi, &.{ .rax, .imm32s }, &.{ 0x15 }, 0, .long, .none },
19 .{ .adc, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 2, .none },20 .{ .adc, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 2, .none, .none },
20 .{ .adc, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 2, .rex },21 .{ .adc, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 2, .rex, .none },
21 .{ .adc, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 2, .none },22 .{ .adc, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 2, .short, .none },
22 .{ .adc, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 2, .none },23 .{ .adc, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 2, .none, .none },
23 .{ .adc, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 2, .long },24 .{ .adc, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 2, .long, .none },
24 .{ .adc, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 2, .none },25 .{ .adc, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 2, .short, .none },
25 .{ .adc, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 2, .none },26 .{ .adc, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 2, .none, .none },
26 .{ .adc, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 2, .long },27 .{ .adc, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 2, .long, .none },
27 .{ .adc, .mr, &.{ .rm8, .r8 }, &.{ 0x10 }, 0, .none },28 .{ .adc, .mr, &.{ .rm8, .r8 }, &.{ 0x10 }, 0, .none, .none },
28 .{ .adc, .mr, &.{ .rm8, .r8 }, &.{ 0x10 }, 0, .rex },29 .{ .adc, .mr, &.{ .rm8, .r8 }, &.{ 0x10 }, 0, .rex, .none },
29 .{ .adc, .mr, &.{ .rm16, .r16 }, &.{ 0x11 }, 0, .none },30 .{ .adc, .mr, &.{ .rm16, .r16 }, &.{ 0x11 }, 0, .short, .none },
30 .{ .adc, .mr, &.{ .rm32, .r32 }, &.{ 0x11 }, 0, .none },31 .{ .adc, .mr, &.{ .rm32, .r32 }, &.{ 0x11 }, 0, .none, .none },
31 .{ .adc, .mr, &.{ .rm64, .r64 }, &.{ 0x11 }, 0, .long },32 .{ .adc, .mr, &.{ .rm64, .r64 }, &.{ 0x11 }, 0, .long, .none },
32 .{ .adc, .rm, &.{ .r8, .rm8 }, &.{ 0x12 }, 0, .none },33 .{ .adc, .rm, &.{ .r8, .rm8 }, &.{ 0x12 }, 0, .none, .none },
33 .{ .adc, .rm, &.{ .r8, .rm8 }, &.{ 0x12 }, 0, .rex },34 .{ .adc, .rm, &.{ .r8, .rm8 }, &.{ 0x12 }, 0, .rex, .none },
34 .{ .adc, .rm, &.{ .r16, .rm16 }, &.{ 0x13 }, 0, .none },35 .{ .adc, .rm, &.{ .r16, .rm16 }, &.{ 0x13 }, 0, .short, .none },
35 .{ .adc, .rm, &.{ .r32, .rm32 }, &.{ 0x13 }, 0, .none },36 .{ .adc, .rm, &.{ .r32, .rm32 }, &.{ 0x13 }, 0, .none, .none },
36 .{ .adc, .rm, &.{ .r64, .rm64 }, &.{ 0x13 }, 0, .long },37 .{ .adc, .rm, &.{ .r64, .rm64 }, &.{ 0x13 }, 0, .long, .none },
3738
38 .{ .add, .zi, &.{ .al, .imm8 }, &.{ 0x04 }, 0, .none },39 .{ .add, .zi, &.{ .al, .imm8 }, &.{ 0x04 }, 0, .none, .none },
39 .{ .add, .zi, &.{ .ax, .imm16 }, &.{ 0x05 }, 0, .none },40 .{ .add, .zi, &.{ .ax, .imm16 }, &.{ 0x05 }, 0, .short, .none },
40 .{ .add, .zi, &.{ .eax, .imm32 }, &.{ 0x05 }, 0, .none },41 .{ .add, .zi, &.{ .eax, .imm32 }, &.{ 0x05 }, 0, .none, .none },
41 .{ .add, .zi, &.{ .rax, .imm32s }, &.{ 0x05 }, 0, .long },42 .{ .add, .zi, &.{ .rax, .imm32s }, &.{ 0x05 }, 0, .long, .none },
42 .{ .add, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 0, .none },43 .{ .add, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 0, .none, .none },
43 .{ .add, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 0, .rex },44 .{ .add, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 0, .rex, .none },
44 .{ .add, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 0, .none },45 .{ .add, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 0, .short, .none },
45 .{ .add, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 0, .none },46 .{ .add, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 0, .none, .none },
46 .{ .add, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 0, .long },47 .{ .add, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 0, .long, .none },
47 .{ .add, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 0, .none },48 .{ .add, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 0, .short, .none },
48 .{ .add, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 0, .none },49 .{ .add, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 0, .none, .none },
49 .{ .add, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 0, .long },50 .{ .add, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 0, .long, .none },
50 .{ .add, .mr, &.{ .rm8, .r8 }, &.{ 0x00 }, 0, .none },51 .{ .add, .mr, &.{ .rm8, .r8 }, &.{ 0x00 }, 0, .none, .none },
51 .{ .add, .mr, &.{ .rm8, .r8 }, &.{ 0x00 }, 0, .rex },52 .{ .add, .mr, &.{ .rm8, .r8 }, &.{ 0x00 }, 0, .rex, .none },
52 .{ .add, .mr, &.{ .rm16, .r16 }, &.{ 0x01 }, 0, .none },53 .{ .add, .mr, &.{ .rm16, .r16 }, &.{ 0x01 }, 0, .short, .none },
53 .{ .add, .mr, &.{ .rm32, .r32 }, &.{ 0x01 }, 0, .none },54 .{ .add, .mr, &.{ .rm32, .r32 }, &.{ 0x01 }, 0, .none, .none },
54 .{ .add, .mr, &.{ .rm64, .r64 }, &.{ 0x01 }, 0, .long },55 .{ .add, .mr, &.{ .rm64, .r64 }, &.{ 0x01 }, 0, .long, .none },
55 .{ .add, .rm, &.{ .r8, .rm8 }, &.{ 0x02 }, 0, .none },56 .{ .add, .rm, &.{ .r8, .rm8 }, &.{ 0x02 }, 0, .none, .none },
56 .{ .add, .rm, &.{ .r8, .rm8 }, &.{ 0x02 }, 0, .rex },57 .{ .add, .rm, &.{ .r8, .rm8 }, &.{ 0x02 }, 0, .rex, .none },
57 .{ .add, .rm, &.{ .r16, .rm16 }, &.{ 0x03 }, 0, .none },58 .{ .add, .rm, &.{ .r16, .rm16 }, &.{ 0x03 }, 0, .short, .none },
58 .{ .add, .rm, &.{ .r32, .rm32 }, &.{ 0x03 }, 0, .none },59 .{ .add, .rm, &.{ .r32, .rm32 }, &.{ 0x03 }, 0, .none, .none },
59 .{ .add, .rm, &.{ .r64, .rm64 }, &.{ 0x03 }, 0, .long },60 .{ .add, .rm, &.{ .r64, .rm64 }, &.{ 0x03 }, 0, .long, .none },
6061
61 .{ .@"and", .zi, &.{ .al, .imm8 }, &.{ 0x24 }, 0, .none },62 .{ .@"and", .zi, &.{ .al, .imm8 }, &.{ 0x24 }, 0, .none, .none },
62 .{ .@"and", .zi, &.{ .ax, .imm16 }, &.{ 0x25 }, 0, .none },63 .{ .@"and", .zi, &.{ .ax, .imm16 }, &.{ 0x25 }, 0, .short, .none },
63 .{ .@"and", .zi, &.{ .eax, .imm32 }, &.{ 0x25 }, 0, .none },64 .{ .@"and", .zi, &.{ .eax, .imm32 }, &.{ 0x25 }, 0, .none, .none },
64 .{ .@"and", .zi, &.{ .rax, .imm32s }, &.{ 0x25 }, 0, .long },65 .{ .@"and", .zi, &.{ .rax, .imm32s }, &.{ 0x25 }, 0, .long, .none },
65 .{ .@"and", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 4, .none },66 .{ .@"and", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 4, .none, .none },
66 .{ .@"and", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 4, .rex },67 .{ .@"and", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 4, .rex, .none },
67 .{ .@"and", .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 4, .none },68 .{ .@"and", .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 4, .short, .none },
68 .{ .@"and", .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 4, .none },69 .{ .@"and", .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 4, .none, .none },
69 .{ .@"and", .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 4, .long },70 .{ .@"and", .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 4, .long, .none },
70 .{ .@"and", .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 4, .none },71 .{ .@"and", .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 4, .short, .none },
71 .{ .@"and", .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 4, .none },72 .{ .@"and", .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 4, .none, .none },
72 .{ .@"and", .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 4, .long },73 .{ .@"and", .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 4, .long, .none },
73 .{ .@"and", .mr, &.{ .rm8, .r8 }, &.{ 0x20 }, 0, .none },74 .{ .@"and", .mr, &.{ .rm8, .r8 }, &.{ 0x20 }, 0, .none, .none },
74 .{ .@"and", .mr, &.{ .rm8, .r8 }, &.{ 0x20 }, 0, .rex },75 .{ .@"and", .mr, &.{ .rm8, .r8 }, &.{ 0x20 }, 0, .rex, .none },
75 .{ .@"and", .mr, &.{ .rm16, .r16 }, &.{ 0x21 }, 0, .none },76 .{ .@"and", .mr, &.{ .rm16, .r16 }, &.{ 0x21 }, 0, .short, .none },
76 .{ .@"and", .mr, &.{ .rm32, .r32 }, &.{ 0x21 }, 0, .none },77 .{ .@"and", .mr, &.{ .rm32, .r32 }, &.{ 0x21 }, 0, .none, .none },
77 .{ .@"and", .mr, &.{ .rm64, .r64 }, &.{ 0x21 }, 0, .long },78 .{ .@"and", .mr, &.{ .rm64, .r64 }, &.{ 0x21 }, 0, .long, .none },
78 .{ .@"and", .rm, &.{ .r8, .rm8 }, &.{ 0x22 }, 0, .none },79 .{ .@"and", .rm, &.{ .r8, .rm8 }, &.{ 0x22 }, 0, .none, .none },
79 .{ .@"and", .rm, &.{ .r8, .rm8 }, &.{ 0x22 }, 0, .rex },80 .{ .@"and", .rm, &.{ .r8, .rm8 }, &.{ 0x22 }, 0, .rex, .none },
80 .{ .@"and", .rm, &.{ .r16, .rm16 }, &.{ 0x23 }, 0, .none },81 .{ .@"and", .rm, &.{ .r16, .rm16 }, &.{ 0x23 }, 0, .short, .none },
81 .{ .@"and", .rm, &.{ .r32, .rm32 }, &.{ 0x23 }, 0, .none },82 .{ .@"and", .rm, &.{ .r32, .rm32 }, &.{ 0x23 }, 0, .none, .none },
82 .{ .@"and", .rm, &.{ .r64, .rm64 }, &.{ 0x23 }, 0, .long },83 .{ .@"and", .rm, &.{ .r64, .rm64 }, &.{ 0x23 }, 0, .long, .none },
8384
84 .{ .bsf, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0xbc }, 0, .none },85 .{ .bsf, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0xbc }, 0, .short, .none },
85 .{ .bsf, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0xbc }, 0, .none },86 .{ .bsf, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0xbc }, 0, .none, .none },
86 .{ .bsf, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0xbc }, 0, .long },87 .{ .bsf, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0xbc }, 0, .long, .none },
8788
88 .{ .bsr, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0xbd }, 0, .none },89 .{ .bsr, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0xbd }, 0, .short, .none },
89 .{ .bsr, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0xbd }, 0, .none },90 .{ .bsr, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0xbd }, 0, .none, .none },
90 .{ .bsr, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0xbd }, 0, .long },91 .{ .bsr, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0xbd }, 0, .long, .none },
9192
92 .{ .bswap, .o, &.{ .r32 }, &.{ 0x0f, 0xc8 }, 0, .none },93 .{ .bswap, .o, &.{ .r32 }, &.{ 0x0f, 0xc8 }, 0, .none, .none },
93 .{ .bswap, .o, &.{ .r64 }, &.{ 0x0f, 0xc8 }, 0, .long },94 .{ .bswap, .o, &.{ .r64 }, &.{ 0x0f, 0xc8 }, 0, .long, .none },
9495
95 .{ .bt, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xa3 }, 0, .none },96 .{ .bt, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xa3 }, 0, .short, .none },
96 .{ .bt, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xa3 }, 0, .none },97 .{ .bt, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xa3 }, 0, .none, .none },
97 .{ .bt, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xa3 }, 0, .long },98 .{ .bt, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xa3 }, 0, .long, .none },
98 .{ .bt, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 4, .none },99 .{ .bt, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 4, .short, .none },
99 .{ .bt, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 4, .none },100 .{ .bt, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 4, .none, .none },
100 .{ .bt, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 4, .long },101 .{ .bt, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 4, .long, .none },
101102
102 .{ .btc, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xbb }, 0, .none },103 .{ .btc, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xbb }, 0, .short, .none },
103 .{ .btc, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xbb }, 0, .none },104 .{ .btc, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xbb }, 0, .none, .none },
104 .{ .btc, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xbb }, 0, .long },105 .{ .btc, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xbb }, 0, .long, .none },
105 .{ .btc, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 7, .none },106 .{ .btc, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 7, .short, .none },
106 .{ .btc, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 7, .none },107 .{ .btc, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 7, .none, .none },
107 .{ .btc, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 7, .long },108 .{ .btc, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 7, .long, .none },
108109
109 .{ .btr, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xb3 }, 0, .none },110 .{ .btr, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xb3 }, 0, .short, .none },
110 .{ .btr, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xb3 }, 0, .none },111 .{ .btr, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xb3 }, 0, .none, .none },
111 .{ .btr, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xb3 }, 0, .long },112 .{ .btr, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xb3 }, 0, .long, .none },
112 .{ .btr, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 6, .none },113 .{ .btr, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 6, .short, .none },
113 .{ .btr, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 6, .none },114 .{ .btr, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 6, .none, .none },
114 .{ .btr, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 6, .long },115 .{ .btr, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 6, .long, .none },
115116
116 .{ .bts, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xab }, 0, .none },117 .{ .bts, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xab }, 0, .short, .none },
117 .{ .bts, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xab }, 0, .none },118 .{ .bts, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xab }, 0, .none, .none },
118 .{ .bts, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xab }, 0, .long },119 .{ .bts, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xab }, 0, .long, .none },
119 .{ .bts, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 5, .none },120 .{ .bts, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 5, .short, .none },
120 .{ .bts, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 5, .none },121 .{ .bts, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 5, .none, .none },
121 .{ .bts, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 5, .long },122 .{ .bts, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 5, .long, .none },
122123
123 // This is M encoding according to Intel, but D makes more sense here.124 // This is M encoding according to Intel, but D makes more sense here.
124 .{ .call, .d, &.{ .rel32 }, &.{ 0xe8 }, 0, .none },125 .{ .call, .d, &.{ .rel32 }, &.{ 0xe8 }, 0, .none, .none },
125 .{ .call, .m, &.{ .rm64 }, &.{ 0xff }, 2, .none },126 .{ .call, .m, &.{ .rm64 }, &.{ 0xff }, 2, .none, .none },
126127
127 .{ .cbw, .np, &.{ .o16 }, &.{ 0x98 }, 0, .none },128 .{ .cbw, .np, &.{ .o16 }, &.{ 0x98 }, 0, .short, .none },
128 .{ .cwde, .np, &.{ .o32 }, &.{ 0x98 }, 0, .none },129 .{ .cwde, .np, &.{ .o32 }, &.{ 0x98 }, 0, .none, .none },
129 .{ .cdqe, .np, &.{ .o64 }, &.{ 0x98 }, 0, .long },130 .{ .cdqe, .np, &.{ .o64 }, &.{ 0x98 }, 0, .long, .none },
130131
131 .{ .cwd, .np, &.{ .o16 }, &.{ 0x99 }, 0, .none },132 .{ .cwd, .np, &.{ .o16 }, &.{ 0x99 }, 0, .short, .none },
132 .{ .cdq, .np, &.{ .o32 }, &.{ 0x99 }, 0, .none },133 .{ .cdq, .np, &.{ .o32 }, &.{ 0x99 }, 0, .none, .none },
133 .{ .cqo, .np, &.{ .o64 }, &.{ 0x99 }, 0, .long },134 .{ .cqo, .np, &.{ .o64 }, &.{ 0x99 }, 0, .long, .none },
134135
135 .{ .cmova, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x47 }, 0, .none },136 .{ .cmova, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x47 }, 0, .short, .none },
136 .{ .cmova, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x47 }, 0, .none },137 .{ .cmova, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x47 }, 0, .none, .none },
137 .{ .cmova, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x47 }, 0, .long },138 .{ .cmova, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x47 }, 0, .long, .none },
138 .{ .cmovae, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .none },139 .{ .cmovae, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .short, .none },
139 .{ .cmovae, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none },140 .{ .cmovae, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none, .none },
140 .{ .cmovae, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long },141 .{ .cmovae, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long, .none },
141 .{ .cmovb, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .none },142 .{ .cmovb, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .short, .none },
142 .{ .cmovb, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none },143 .{ .cmovb, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none, .none },
143 .{ .cmovb, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long },144 .{ .cmovb, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long, .none },
144 .{ .cmovbe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x46 }, 0, .none },145 .{ .cmovbe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x46 }, 0, .short, .none },
145 .{ .cmovbe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x46 }, 0, .none },146 .{ .cmovbe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x46 }, 0, .none, .none },
146 .{ .cmovbe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x46 }, 0, .long },147 .{ .cmovbe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x46 }, 0, .long, .none },
147 .{ .cmovc, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .none },148 .{ .cmovc, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .short, .none },
148 .{ .cmovc, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none },149 .{ .cmovc, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none, .none },
149 .{ .cmovc, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long },150 .{ .cmovc, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long, .none },
150 .{ .cmove, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x44 }, 0, .none },151 .{ .cmove, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x44 }, 0, .short, .none },
151 .{ .cmove, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x44 }, 0, .none },152 .{ .cmove, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x44 }, 0, .none, .none },
152 .{ .cmove, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x44 }, 0, .long },153 .{ .cmove, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x44 }, 0, .long, .none },
153 .{ .cmovg, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4f }, 0, .none },154 .{ .cmovg, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4f }, 0, .short, .none },
154 .{ .cmovg, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4f }, 0, .none },155 .{ .cmovg, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4f }, 0, .none, .none },
155 .{ .cmovg, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4f }, 0, .long },156 .{ .cmovg, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4f }, 0, .long, .none },
156 .{ .cmovge, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4d }, 0, .none },157 .{ .cmovge, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4d }, 0, .short, .none },
157 .{ .cmovge, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4d }, 0, .none },158 .{ .cmovge, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4d }, 0, .none, .none },
158 .{ .cmovge, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4d }, 0, .long },159 .{ .cmovge, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4d }, 0, .long, .none },
159 .{ .cmovl, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4c }, 0, .none },160 .{ .cmovl, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4c }, 0, .short, .none },
160 .{ .cmovl, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4c }, 0, .none },161 .{ .cmovl, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4c }, 0, .none, .none },
161 .{ .cmovl, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4c }, 0, .long },162 .{ .cmovl, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4c }, 0, .long, .none },
162 .{ .cmovle, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4e }, 0, .none },163 .{ .cmovle, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4e }, 0, .short, .none },
163 .{ .cmovle, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4e }, 0, .none },164 .{ .cmovle, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4e }, 0, .none, .none },
164 .{ .cmovle, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4e }, 0, .long },165 .{ .cmovle, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4e }, 0, .long, .none },
165 .{ .cmovna, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x46 }, 0, .none },166 .{ .cmovna, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x46 }, 0, .short, .none },
166 .{ .cmovna, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x46 }, 0, .none },167 .{ .cmovna, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x46 }, 0, .none, .none },
167 .{ .cmovna, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x46 }, 0, .long },168 .{ .cmovna, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x46 }, 0, .long, .none },
168 .{ .cmovnae, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .none },169 .{ .cmovnae, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .short, .none },
169 .{ .cmovnae, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none },170 .{ .cmovnae, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none, .none },
170 .{ .cmovnae, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long },171 .{ .cmovnae, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long, .none },
171 .{ .cmovnb, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .none },172 .{ .cmovnb, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .short, .none },
172 .{ .cmovnb, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none },173 .{ .cmovnb, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none, .none },
173 .{ .cmovnb, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long },174 .{ .cmovnb, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long, .none },
174 .{ .cmovnbe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x47 }, 0, .none },175 .{ .cmovnbe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x47 }, 0, .short, .none },
175 .{ .cmovnbe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x47 }, 0, .none },176 .{ .cmovnbe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x47 }, 0, .none, .none },
176 .{ .cmovnbe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x47 }, 0, .long },177 .{ .cmovnbe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x47 }, 0, .long, .none },
177 .{ .cmovnc, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .none },178 .{ .cmovnc, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .short, .none },
178 .{ .cmovnc, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none },179 .{ .cmovnc, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none, .none },
179 .{ .cmovnc, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long },180 .{ .cmovnc, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long, .none },
180 .{ .cmovne, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x45 }, 0, .none },181 .{ .cmovne, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x45 }, 0, .short, .none },
181 .{ .cmovne, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x45 }, 0, .none },182 .{ .cmovne, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x45 }, 0, .none, .none },
182 .{ .cmovne, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x45 }, 0, .long },183 .{ .cmovne, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x45 }, 0, .long, .none },
183 .{ .cmovng, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4e }, 0, .none },184 .{ .cmovng, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4e }, 0, .short, .none },
184 .{ .cmovng, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4e }, 0, .none },185 .{ .cmovng, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4e }, 0, .none, .none },
185 .{ .cmovng, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4e }, 0, .long },186 .{ .cmovng, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4e }, 0, .long, .none },
186 .{ .cmovnge, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4c }, 0, .none },187 .{ .cmovnge, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4c }, 0, .short, .none },
187 .{ .cmovnge, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4c }, 0, .none },188 .{ .cmovnge, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4c }, 0, .none, .none },
188 .{ .cmovnge, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4c }, 0, .long },189 .{ .cmovnge, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4c }, 0, .long, .none },
189 .{ .cmovnl, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4d }, 0, .none },190 .{ .cmovnl, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4d }, 0, .short, .none },
190 .{ .cmovnl, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4d }, 0, .none },191 .{ .cmovnl, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4d }, 0, .none, .none },
191 .{ .cmovnl, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4d }, 0, .long },192 .{ .cmovnl, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4d }, 0, .long, .none },
192 .{ .cmovnle, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4f }, 0, .none },193 .{ .cmovnle, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4f }, 0, .short, .none },
193 .{ .cmovnle, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4f }, 0, .none },194 .{ .cmovnle, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4f }, 0, .none, .none },
194 .{ .cmovnle, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4f }, 0, .long },195 .{ .cmovnle, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4f }, 0, .long, .none },
195 .{ .cmovno, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x41 }, 0, .none },196 .{ .cmovno, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x41 }, 0, .short, .none },
196 .{ .cmovno, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x41 }, 0, .none },197 .{ .cmovno, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x41 }, 0, .none, .none },
197 .{ .cmovno, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x41 }, 0, .long },198 .{ .cmovno, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x41 }, 0, .long, .none },
198 .{ .cmovnp, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4b }, 0, .none },199 .{ .cmovnp, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4b }, 0, .short, .none },
199 .{ .cmovnp, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4b }, 0, .none },200 .{ .cmovnp, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4b }, 0, .none, .none },
200 .{ .cmovnp, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4b }, 0, .long },201 .{ .cmovnp, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4b }, 0, .long, .none },
201 .{ .cmovns, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x49 }, 0, .none },202 .{ .cmovns, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x49 }, 0, .short, .none },
202 .{ .cmovns, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x49 }, 0, .none },203 .{ .cmovns, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x49 }, 0, .none, .none },
203 .{ .cmovns, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x49 }, 0, .long },204 .{ .cmovns, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x49 }, 0, .long, .none },
204 .{ .cmovnz, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x45 }, 0, .none },205 .{ .cmovnz, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x45 }, 0, .short, .none },
205 .{ .cmovnz, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x45 }, 0, .none },206 .{ .cmovnz, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x45 }, 0, .none, .none },
206 .{ .cmovnz, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x45 }, 0, .long },207 .{ .cmovnz, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x45 }, 0, .long, .none },
207 .{ .cmovo, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x40 }, 0, .none },208 .{ .cmovo, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x40 }, 0, .short, .none },
208 .{ .cmovo, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x40 }, 0, .none },209 .{ .cmovo, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x40 }, 0, .none, .none },
209 .{ .cmovo, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x40 }, 0, .long },210 .{ .cmovo, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x40 }, 0, .long, .none },
210 .{ .cmovp, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4a }, 0, .none },211 .{ .cmovp, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4a }, 0, .short, .none },
211 .{ .cmovp, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4a }, 0, .none },212 .{ .cmovp, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4a }, 0, .none, .none },
212 .{ .cmovp, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4a }, 0, .long },213 .{ .cmovp, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4a }, 0, .long, .none },
213 .{ .cmovpe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4a }, 0, .none },214 .{ .cmovpe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4a }, 0, .short, .none },
214 .{ .cmovpe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4a }, 0, .none },215 .{ .cmovpe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4a }, 0, .none, .none },
215 .{ .cmovpe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4a }, 0, .long },216 .{ .cmovpe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4a }, 0, .long, .none },
216 .{ .cmovpo, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4b }, 0, .none },217 .{ .cmovpo, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4b }, 0, .short, .none },
217 .{ .cmovpo, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4b }, 0, .none },218 .{ .cmovpo, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4b }, 0, .none, .none },
218 .{ .cmovpo, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4b }, 0, .long },219 .{ .cmovpo, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4b }, 0, .long, .none },
219 .{ .cmovs, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x48 }, 0, .none },220 .{ .cmovs, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x48 }, 0, .short, .none },
220 .{ .cmovs, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x48 }, 0, .none },221 .{ .cmovs, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x48 }, 0, .none, .none },
221 .{ .cmovs, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x48 }, 0, .long },222 .{ .cmovs, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x48 }, 0, .long, .none },
222 .{ .cmovz, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x44 }, 0, .none },223 .{ .cmovz, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x44 }, 0, .short, .none },
223 .{ .cmovz, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x44 }, 0, .none },224 .{ .cmovz, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x44 }, 0, .none, .none },
224 .{ .cmovz, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x44 }, 0, .long },225 .{ .cmovz, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x44 }, 0, .long, .none },
225226
226 .{ .cmp, .zi, &.{ .al, .imm8 }, &.{ 0x3c }, 0, .none },227 .{ .cmp, .zi, &.{ .al, .imm8 }, &.{ 0x3c }, 0, .none, .none },
227 .{ .cmp, .zi, &.{ .ax, .imm16 }, &.{ 0x3d }, 0, .none },228 .{ .cmp, .zi, &.{ .ax, .imm16 }, &.{ 0x3d }, 0, .short, .none },
228 .{ .cmp, .zi, &.{ .eax, .imm32 }, &.{ 0x3d }, 0, .none },229 .{ .cmp, .zi, &.{ .eax, .imm32 }, &.{ 0x3d }, 0, .none, .none },
229 .{ .cmp, .zi, &.{ .rax, .imm32s }, &.{ 0x3d }, 0, .long },230 .{ .cmp, .zi, &.{ .rax, .imm32s }, &.{ 0x3d }, 0, .long, .none },
230 .{ .cmp, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 7, .none },231 .{ .cmp, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 7, .none, .none },
231 .{ .cmp, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 7, .rex },232 .{ .cmp, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 7, .rex, .none },
232 .{ .cmp, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 7, .none },233 .{ .cmp, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 7, .short, .none },
233 .{ .cmp, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 7, .none },234 .{ .cmp, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 7, .none, .none },
234 .{ .cmp, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 7, .long },235 .{ .cmp, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 7, .long, .none },
235 .{ .cmp, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 7, .none },236 .{ .cmp, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 7, .short, .none },
236 .{ .cmp, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 7, .none },237 .{ .cmp, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 7, .none, .none },
237 .{ .cmp, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 7, .long },238 .{ .cmp, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 7, .long, .none },
238 .{ .cmp, .mr, &.{ .rm8, .r8 }, &.{ 0x38 }, 0, .none },239 .{ .cmp, .mr, &.{ .rm8, .r8 }, &.{ 0x38 }, 0, .none, .none },
239 .{ .cmp, .mr, &.{ .rm8, .r8 }, &.{ 0x38 }, 0, .rex },240 .{ .cmp, .mr, &.{ .rm8, .r8 }, &.{ 0x38 }, 0, .rex, .none },
240 .{ .cmp, .mr, &.{ .rm16, .r16 }, &.{ 0x39 }, 0, .none },241 .{ .cmp, .mr, &.{ .rm16, .r16 }, &.{ 0x39 }, 0, .short, .none },
241 .{ .cmp, .mr, &.{ .rm32, .r32 }, &.{ 0x39 }, 0, .none },242 .{ .cmp, .mr, &.{ .rm32, .r32 }, &.{ 0x39 }, 0, .none, .none },
242 .{ .cmp, .mr, &.{ .rm64, .r64 }, &.{ 0x39 }, 0, .long },243 .{ .cmp, .mr, &.{ .rm64, .r64 }, &.{ 0x39 }, 0, .long, .none },
243 .{ .cmp, .rm, &.{ .r8, .rm8 }, &.{ 0x3a }, 0, .none },244 .{ .cmp, .rm, &.{ .r8, .rm8 }, &.{ 0x3a }, 0, .none, .none },
244 .{ .cmp, .rm, &.{ .r8, .rm8 }, &.{ 0x3a }, 0, .rex },245 .{ .cmp, .rm, &.{ .r8, .rm8 }, &.{ 0x3a }, 0, .rex, .none },
245 .{ .cmp, .rm, &.{ .r16, .rm16 }, &.{ 0x3b }, 0, .none },246 .{ .cmp, .rm, &.{ .r16, .rm16 }, &.{ 0x3b }, 0, .short, .none },
246 .{ .cmp, .rm, &.{ .r32, .rm32 }, &.{ 0x3b }, 0, .none },247 .{ .cmp, .rm, &.{ .r32, .rm32 }, &.{ 0x3b }, 0, .none, .none },
247 .{ .cmp, .rm, &.{ .r64, .rm64 }, &.{ 0x3b }, 0, .long },248 .{ .cmp, .rm, &.{ .r64, .rm64 }, &.{ 0x3b }, 0, .long, .none },
248249
249 .{ .cmps, .np, &.{ .m8, .m8 }, &.{ 0xa6 }, 0, .none },250 .{ .cmps, .np, &.{ .m8, .m8 }, &.{ 0xa6 }, 0, .none, .none },
250 .{ .cmps, .np, &.{ .m16, .m16 }, &.{ 0xa7 }, 0, .none },251 .{ .cmps, .np, &.{ .m16, .m16 }, &.{ 0xa7 }, 0, .short, .none },
251 .{ .cmps, .np, &.{ .m32, .m32 }, &.{ 0xa7 }, 0, .none },252 .{ .cmps, .np, &.{ .m32, .m32 }, &.{ 0xa7 }, 0, .none, .none },
252 .{ .cmps, .np, &.{ .m64, .m64 }, &.{ 0xa7 }, 0, .long },253 .{ .cmps, .np, &.{ .m64, .m64 }, &.{ 0xa7 }, 0, .long, .none },
253254
254 .{ .cmpsb, .np, &.{}, &.{ 0xa6 }, 0, .none },255 .{ .cmpsb, .np, &.{}, &.{ 0xa6 }, 0, .none, .none },
255 .{ .cmpsw, .np, &.{}, &.{ 0xa7 }, 0, .short },256 .{ .cmpsw, .np, &.{}, &.{ 0xa7 }, 0, .short, .none },
256 .{ .cmpsd, .np, &.{}, &.{ 0xa7 }, 0, .none },257 .{ .cmpsd, .np, &.{}, &.{ 0xa7 }, 0, .none, .none },
257 .{ .cmpsq, .np, &.{}, &.{ 0xa7 }, 0, .long },258 .{ .cmpsq, .np, &.{}, &.{ 0xa7 }, 0, .long, .none },
258259
259 .{ .cmpxchg, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xb0 }, 0, .none },260 .{ .cmpxchg, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xb0 }, 0, .none, .none },
260 .{ .cmpxchg, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xb0 }, 0, .rex },261 .{ .cmpxchg, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xb0 }, 0, .rex, .none },
261 .{ .cmpxchg, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xb1 }, 0, .none },262 .{ .cmpxchg, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xb1 }, 0, .short, .none },
262 .{ .cmpxchg, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xb1 }, 0, .none },263 .{ .cmpxchg, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xb1 }, 0, .none, .none },
263 .{ .cmpxchg, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xb1 }, 0, .long },264 .{ .cmpxchg, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xb1 }, 0, .long, .none },
264265
265 .{ .cmpxchg8b , .m, &.{ .m64 }, &.{ 0x0f, 0xc7 }, 1, .none },266 .{ .cmpxchg8b, .m, &.{ .m64 }, &.{ 0x0f, 0xc7 }, 1, .none, .none },
266 .{ .cmpxchg16b, .m, &.{ .m128 }, &.{ 0x0f, 0xc7 }, 1, .long },267 .{ .cmpxchg16b, .m, &.{ .m128 }, &.{ 0x0f, 0xc7 }, 1, .long, .none },
267268
268 .{ .div, .m, &.{ .rm8 }, &.{ 0xf6 }, 6, .none },269 .{ .div, .m, &.{ .rm8 }, &.{ 0xf6 }, 6, .none, .none },
269 .{ .div, .m, &.{ .rm8 }, &.{ 0xf6 }, 6, .rex },270 .{ .div, .m, &.{ .rm8 }, &.{ 0xf6 }, 6, .rex, .none },
270 .{ .div, .m, &.{ .rm16 }, &.{ 0xf7 }, 6, .none },271 .{ .div, .m, &.{ .rm16 }, &.{ 0xf7 }, 6, .short, .none },
271 .{ .div, .m, &.{ .rm32 }, &.{ 0xf7 }, 6, .none },272 .{ .div, .m, &.{ .rm32 }, &.{ 0xf7 }, 6, .none, .none },
272 .{ .div, .m, &.{ .rm64 }, &.{ 0xf7 }, 6, .long },273 .{ .div, .m, &.{ .rm64 }, &.{ 0xf7 }, 6, .long, .none },
273274
274 .{ .fisttp, .m, &.{ .m16 }, &.{ 0xdf }, 1, .fpu },275 .{ .fisttp, .m, &.{ .m16 }, &.{ 0xdf }, 1, .none, .x87 },
275 .{ .fisttp, .m, &.{ .m32 }, &.{ 0xdb }, 1, .fpu },276 .{ .fisttp, .m, &.{ .m32 }, &.{ 0xdb }, 1, .none, .x87 },
276 .{ .fisttp, .m, &.{ .m64 }, &.{ 0xdd }, 1, .fpu },277 .{ .fisttp, .m, &.{ .m64 }, &.{ 0xdd }, 1, .none, .x87 },
277278
278 .{ .fld, .m, &.{ .m32 }, &.{ 0xd9 }, 0, .fpu },279 .{ .fld, .m, &.{ .m32 }, &.{ 0xd9 }, 0, .none, .x87 },
279 .{ .fld, .m, &.{ .m64 }, &.{ 0xdd }, 0, .fpu },280 .{ .fld, .m, &.{ .m64 }, &.{ 0xdd }, 0, .none, .x87 },
280 .{ .fld, .m, &.{ .m80 }, &.{ 0xdb }, 5, .fpu },281 .{ .fld, .m, &.{ .m80 }, &.{ 0xdb }, 5, .none, .x87 },
281282
282 .{ .idiv, .m, &.{ .rm8 }, &.{ 0xf6 }, 7, .none },283 .{ .idiv, .m, &.{ .rm8 }, &.{ 0xf6 }, 7, .none, .none },
283 .{ .idiv, .m, &.{ .rm8 }, &.{ 0xf6 }, 7, .rex },284 .{ .idiv, .m, &.{ .rm8 }, &.{ 0xf6 }, 7, .rex, .none },
284 .{ .idiv, .m, &.{ .rm16 }, &.{ 0xf7 }, 7, .none },285 .{ .idiv, .m, &.{ .rm16 }, &.{ 0xf7 }, 7, .short, .none },
285 .{ .idiv, .m, &.{ .rm32 }, &.{ 0xf7 }, 7, .none },286 .{ .idiv, .m, &.{ .rm32 }, &.{ 0xf7 }, 7, .none, .none },
286 .{ .idiv, .m, &.{ .rm64 }, &.{ 0xf7 }, 7, .long },287 .{ .idiv, .m, &.{ .rm64 }, &.{ 0xf7 }, 7, .long, .none },
287288
288 .{ .imul, .m, &.{ .rm8 }, &.{ 0xf6 }, 5, .none },289 .{ .imul, .m, &.{ .rm8 }, &.{ 0xf6 }, 5, .none, .none },
289 .{ .imul, .m, &.{ .rm8 }, &.{ 0xf6 }, 5, .rex },290 .{ .imul, .m, &.{ .rm8 }, &.{ 0xf6 }, 5, .rex, .none },
290 .{ .imul, .m, &.{ .rm16, }, &.{ 0xf7 }, 5, .none },291 .{ .imul, .m, &.{ .rm16, }, &.{ 0xf7 }, 5, .short, .none },
291 .{ .imul, .m, &.{ .rm32, }, &.{ 0xf7 }, 5, .none },292 .{ .imul, .m, &.{ .rm32, }, &.{ 0xf7 }, 5, .none, .none },
292 .{ .imul, .m, &.{ .rm64, }, &.{ 0xf7 }, 5, .long },293 .{ .imul, .m, &.{ .rm64, }, &.{ 0xf7 }, 5, .long, .none },
293 .{ .imul, .rm, &.{ .r16, .rm16, }, &.{ 0x0f, 0xaf }, 0, .none },294 .{ .imul, .rm, &.{ .r16, .rm16, }, &.{ 0x0f, 0xaf }, 0, .short, .none },
294 .{ .imul, .rm, &.{ .r32, .rm32, }, &.{ 0x0f, 0xaf }, 0, .none },295 .{ .imul, .rm, &.{ .r32, .rm32, }, &.{ 0x0f, 0xaf }, 0, .none, .none },
295 .{ .imul, .rm, &.{ .r64, .rm64, }, &.{ 0x0f, 0xaf }, 0, .long },296 .{ .imul, .rm, &.{ .r64, .rm64, }, &.{ 0x0f, 0xaf }, 0, .long, .none },
296 .{ .imul, .rmi, &.{ .r16, .rm16, .imm8s }, &.{ 0x6b }, 0, .none },297 .{ .imul, .rmi, &.{ .r16, .rm16, .imm8s }, &.{ 0x6b }, 0, .short, .none },
297 .{ .imul, .rmi, &.{ .r32, .rm32, .imm8s }, &.{ 0x6b }, 0, .none },298 .{ .imul, .rmi, &.{ .r32, .rm32, .imm8s }, &.{ 0x6b }, 0, .none, .none },
298 .{ .imul, .rmi, &.{ .r64, .rm64, .imm8s }, &.{ 0x6b }, 0, .long },299 .{ .imul, .rmi, &.{ .r64, .rm64, .imm8s }, &.{ 0x6b }, 0, .long, .none },
299 .{ .imul, .rmi, &.{ .r16, .rm16, .imm16 }, &.{ 0x69 }, 0, .none },300 .{ .imul, .rmi, &.{ .r16, .rm16, .imm16 }, &.{ 0x69 }, 0, .short, .none },
300 .{ .imul, .rmi, &.{ .r32, .rm32, .imm32 }, &.{ 0x69 }, 0, .none },301 .{ .imul, .rmi, &.{ .r32, .rm32, .imm32 }, &.{ 0x69 }, 0, .none, .none },
301 .{ .imul, .rmi, &.{ .r64, .rm64, .imm32 }, &.{ 0x69 }, 0, .long },302 .{ .imul, .rmi, &.{ .r64, .rm64, .imm32 }, &.{ 0x69 }, 0, .long, .none },
302303
303 .{ .int3, .np, &.{}, &.{ 0xcc }, 0, .none },304 .{ .int3, .np, &.{}, &.{ 0xcc }, 0, .none, .none },
304305
305 .{ .ja, .d, &.{ .rel32 }, &.{ 0x0f, 0x87 }, 0, .none },306 .{ .ja, .d, &.{ .rel32 }, &.{ 0x0f, 0x87 }, 0, .none, .none },
306 .{ .jae, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none },307 .{ .jae, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none, .none },
307 .{ .jb, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none },308 .{ .jb, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none, .none },
308 .{ .jbe, .d, &.{ .rel32 }, &.{ 0x0f, 0x86 }, 0, .none },309 .{ .jbe, .d, &.{ .rel32 }, &.{ 0x0f, 0x86 }, 0, .none, .none },
309 .{ .jc, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none },310 .{ .jc, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none, .none },
310 .{ .jrcxz, .d, &.{ .rel32 }, &.{ 0xe3 }, 0, .none },311 .{ .jrcxz, .d, &.{ .rel32 }, &.{ 0xe3 }, 0, .none, .none },
311 .{ .je, .d, &.{ .rel32 }, &.{ 0x0f, 0x84 }, 0, .none },312 .{ .je, .d, &.{ .rel32 }, &.{ 0x0f, 0x84 }, 0, .none, .none },
312 .{ .jg, .d, &.{ .rel32 }, &.{ 0x0f, 0x8f }, 0, .none },313 .{ .jg, .d, &.{ .rel32 }, &.{ 0x0f, 0x8f }, 0, .none, .none },
313 .{ .jge, .d, &.{ .rel32 }, &.{ 0x0f, 0x8d }, 0, .none },314 .{ .jge, .d, &.{ .rel32 }, &.{ 0x0f, 0x8d }, 0, .none, .none },
314 .{ .jl, .d, &.{ .rel32 }, &.{ 0x0f, 0x8c }, 0, .none },315 .{ .jl, .d, &.{ .rel32 }, &.{ 0x0f, 0x8c }, 0, .none, .none },
315 .{ .jle, .d, &.{ .rel32 }, &.{ 0x0f, 0x8e }, 0, .none },316 .{ .jle, .d, &.{ .rel32 }, &.{ 0x0f, 0x8e }, 0, .none, .none },
316 .{ .jna, .d, &.{ .rel32 }, &.{ 0x0f, 0x86 }, 0, .none },317 .{ .jna, .d, &.{ .rel32 }, &.{ 0x0f, 0x86 }, 0, .none, .none },
317 .{ .jnae, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none },318 .{ .jnae, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none, .none },
318 .{ .jnb, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none },319 .{ .jnb, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none, .none },
319 .{ .jnbe, .d, &.{ .rel32 }, &.{ 0x0f, 0x87 }, 0, .none },320 .{ .jnbe, .d, &.{ .rel32 }, &.{ 0x0f, 0x87 }, 0, .none, .none },
320 .{ .jnc, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none },321 .{ .jnc, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none, .none },
321 .{ .jne, .d, &.{ .rel32 }, &.{ 0x0f, 0x85 }, 0, .none },322 .{ .jne, .d, &.{ .rel32 }, &.{ 0x0f, 0x85 }, 0, .none, .none },
322 .{ .jng, .d, &.{ .rel32 }, &.{ 0x0f, 0x8e }, 0, .none },323 .{ .jng, .d, &.{ .rel32 }, &.{ 0x0f, 0x8e }, 0, .none, .none },
323 .{ .jnge, .d, &.{ .rel32 }, &.{ 0x0f, 0x8c }, 0, .none },324 .{ .jnge, .d, &.{ .rel32 }, &.{ 0x0f, 0x8c }, 0, .none, .none },
324 .{ .jnl, .d, &.{ .rel32 }, &.{ 0x0f, 0x8d }, 0, .none },325 .{ .jnl, .d, &.{ .rel32 }, &.{ 0x0f, 0x8d }, 0, .none, .none },
325 .{ .jnle, .d, &.{ .rel32 }, &.{ 0x0f, 0x8f }, 0, .none },326 .{ .jnle, .d, &.{ .rel32 }, &.{ 0x0f, 0x8f }, 0, .none, .none },
326 .{ .jno, .d, &.{ .rel32 }, &.{ 0x0f, 0x81 }, 0, .none },327 .{ .jno, .d, &.{ .rel32 }, &.{ 0x0f, 0x81 }, 0, .none, .none },
327 .{ .jnp, .d, &.{ .rel32 }, &.{ 0x0f, 0x8b }, 0, .none },328 .{ .jnp, .d, &.{ .rel32 }, &.{ 0x0f, 0x8b }, 0, .none, .none },
328 .{ .jns, .d, &.{ .rel32 }, &.{ 0x0f, 0x89 }, 0, .none },329 .{ .jns, .d, &.{ .rel32 }, &.{ 0x0f, 0x89 }, 0, .none, .none },
329 .{ .jnz, .d, &.{ .rel32 }, &.{ 0x0f, 0x85 }, 0, .none },330 .{ .jnz, .d, &.{ .rel32 }, &.{ 0x0f, 0x85 }, 0, .none, .none },
330 .{ .jo, .d, &.{ .rel32 }, &.{ 0x0f, 0x80 }, 0, .none },331 .{ .jo, .d, &.{ .rel32 }, &.{ 0x0f, 0x80 }, 0, .none, .none },
331 .{ .jp, .d, &.{ .rel32 }, &.{ 0x0f, 0x8a }, 0, .none },332 .{ .jp, .d, &.{ .rel32 }, &.{ 0x0f, 0x8a }, 0, .none, .none },
332 .{ .jpe, .d, &.{ .rel32 }, &.{ 0x0f, 0x8a }, 0, .none },333 .{ .jpe, .d, &.{ .rel32 }, &.{ 0x0f, 0x8a }, 0, .none, .none },
333 .{ .jpo, .d, &.{ .rel32 }, &.{ 0x0f, 0x8b }, 0, .none },334 .{ .jpo, .d, &.{ .rel32 }, &.{ 0x0f, 0x8b }, 0, .none, .none },
334 .{ .js, .d, &.{ .rel32 }, &.{ 0x0f, 0x88 }, 0, .none },335 .{ .js, .d, &.{ .rel32 }, &.{ 0x0f, 0x88 }, 0, .none, .none },
335 .{ .jz, .d, &.{ .rel32 }, &.{ 0x0f, 0x84 }, 0, .none },336 .{ .jz, .d, &.{ .rel32 }, &.{ 0x0f, 0x84 }, 0, .none, .none },
336337
337 .{ .jmp, .d, &.{ .rel32 }, &.{ 0xe9 }, 0, .none },338 .{ .jmp, .d, &.{ .rel32 }, &.{ 0xe9 }, 0, .none, .none },
338 .{ .jmp, .m, &.{ .rm64 }, &.{ 0xff }, 4, .none },339 .{ .jmp, .m, &.{ .rm64 }, &.{ 0xff }, 4, .none, .none },
339340
340 .{ .lea, .rm, &.{ .r16, .m }, &.{ 0x8d }, 0, .none },341 .{ .lea, .rm, &.{ .r16, .m }, &.{ 0x8d }, 0, .short, .none },
341 .{ .lea, .rm, &.{ .r32, .m }, &.{ 0x8d }, 0, .none },342 .{ .lea, .rm, &.{ .r32, .m }, &.{ 0x8d }, 0, .none, .none },
342 .{ .lea, .rm, &.{ .r64, .m }, &.{ 0x8d }, 0, .long },343 .{ .lea, .rm, &.{ .r64, .m }, &.{ 0x8d }, 0, .long, .none },
343344
344 .{ .lfence, .np, &.{}, &.{ 0x0f, 0xae, 0xe8 }, 0, .none },345 .{ .lfence, .np, &.{}, &.{ 0x0f, 0xae, 0xe8 }, 0, .none, .none },
345346
346 .{ .lods, .np, &.{ .m8 }, &.{ 0xac }, 0, .none },347 .{ .lods, .np, &.{ .m8 }, &.{ 0xac }, 0, .none, .none },
347 .{ .lods, .np, &.{ .m16 }, &.{ 0xad }, 0, .none },348 .{ .lods, .np, &.{ .m16 }, &.{ 0xad }, 0, .short, .none },
348 .{ .lods, .np, &.{ .m32 }, &.{ 0xad }, 0, .none },349 .{ .lods, .np, &.{ .m32 }, &.{ 0xad }, 0, .none, .none },
349 .{ .lods, .np, &.{ .m64 }, &.{ 0xad }, 0, .long },350 .{ .lods, .np, &.{ .m64 }, &.{ 0xad }, 0, .long, .none },
350351
351 .{ .lodsb, .np, &.{}, &.{ 0xac }, 0, .none },352 .{ .lodsb, .np, &.{}, &.{ 0xac }, 0, .none, .none },
352 .{ .lodsw, .np, &.{}, &.{ 0xad }, 0, .short },353 .{ .lodsw, .np, &.{}, &.{ 0xad }, 0, .short, .none },
353 .{ .lodsd, .np, &.{}, &.{ 0xad }, 0, .none },354 .{ .lodsd, .np, &.{}, &.{ 0xad }, 0, .none, .none },
354 .{ .lodsq, .np, &.{}, &.{ 0xad }, 0, .long },355 .{ .lodsq, .np, &.{}, &.{ 0xad }, 0, .long, .none },
355356
356 .{ .lzcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .none },357 .{ .lzcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .short, .none },
357 .{ .lzcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .none },358 .{ .lzcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .none, .none },
358 .{ .lzcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .long },359 .{ .lzcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .long, .none },
359360
360 .{ .mfence, .np, &.{}, &.{ 0x0f, 0xae, 0xf0 }, 0, .none },361 .{ .mfence, .np, &.{}, &.{ 0x0f, 0xae, 0xf0 }, 0, .none, .none },
361362
362 .{ .mov, .mr, &.{ .rm8, .r8 }, &.{ 0x88 }, 0, .none },363 .{ .mov, .mr, &.{ .rm8, .r8 }, &.{ 0x88 }, 0, .none, .none },
363 .{ .mov, .mr, &.{ .rm8, .r8 }, &.{ 0x88 }, 0, .rex },364 .{ .mov, .mr, &.{ .rm8, .r8 }, &.{ 0x88 }, 0, .rex, .none },
364 .{ .mov, .mr, &.{ .rm16, .r16 }, &.{ 0x89 }, 0, .none },365 .{ .mov, .mr, &.{ .rm16, .r16 }, &.{ 0x89 }, 0, .short, .none },
365 .{ .mov, .mr, &.{ .rm32, .r32 }, &.{ 0x89 }, 0, .none },366 .{ .mov, .mr, &.{ .rm32, .r32 }, &.{ 0x89 }, 0, .none, .none },
366 .{ .mov, .mr, &.{ .rm64, .r64 }, &.{ 0x89 }, 0, .long },367 .{ .mov, .mr, &.{ .rm64, .r64 }, &.{ 0x89 }, 0, .long, .none },
367 .{ .mov, .rm, &.{ .r8, .rm8 }, &.{ 0x8a }, 0, .none },368 .{ .mov, .rm, &.{ .r8, .rm8 }, &.{ 0x8a }, 0, .none, .none },
368 .{ .mov, .rm, &.{ .r8, .rm8 }, &.{ 0x8a }, 0, .rex },369 .{ .mov, .rm, &.{ .r8, .rm8 }, &.{ 0x8a }, 0, .rex, .none },
369 .{ .mov, .rm, &.{ .r16, .rm16 }, &.{ 0x8b }, 0, .none },370 .{ .mov, .rm, &.{ .r16, .rm16 }, &.{ 0x8b }, 0, .short, .none },
370 .{ .mov, .rm, &.{ .r32, .rm32 }, &.{ 0x8b }, 0, .none },371 .{ .mov, .rm, &.{ .r32, .rm32 }, &.{ 0x8b }, 0, .none, .none },
371 .{ .mov, .rm, &.{ .r64, .rm64 }, &.{ 0x8b }, 0, .long },372 .{ .mov, .rm, &.{ .r64, .rm64 }, &.{ 0x8b }, 0, .long, .none },
372 .{ .mov, .mr, &.{ .rm16, .sreg }, &.{ 0x8c }, 0, .none },373 .{ .mov, .mr, &.{ .rm16, .sreg }, &.{ 0x8c }, 0, .short, .none },
373 .{ .mov, .mr, &.{ .rm64, .sreg }, &.{ 0x8c }, 0, .long },374 .{ .mov, .mr, &.{ .r32_m16, .sreg }, &.{ 0x8c }, 0, .none, .none },
374 .{ .mov, .rm, &.{ .sreg, .rm16 }, &.{ 0x8e }, 0, .none },375 .{ .mov, .mr, &.{ .r64_m16, .sreg }, &.{ 0x8c }, 0, .long, .none },
375 .{ .mov, .rm, &.{ .sreg, .rm64 }, &.{ 0x8e }, 0, .long },376 .{ .mov, .rm, &.{ .sreg, .rm16 }, &.{ 0x8e }, 0, .short, .none },
376 .{ .mov, .fd, &.{ .al, .moffs }, &.{ 0xa0 }, 0, .none },377 .{ .mov, .rm, &.{ .sreg, .r32_m16 }, &.{ 0x8e }, 0, .none, .none },
377 .{ .mov, .fd, &.{ .ax, .moffs }, &.{ 0xa1 }, 0, .none },378 .{ .mov, .rm, &.{ .sreg, .r64_m16 }, &.{ 0x8e }, 0, .long, .none },
378 .{ .mov, .fd, &.{ .eax, .moffs }, &.{ 0xa1 }, 0, .none },379 .{ .mov, .fd, &.{ .al, .moffs }, &.{ 0xa0 }, 0, .none, .none },
379 .{ .mov, .fd, &.{ .rax, .moffs }, &.{ 0xa1 }, 0, .long },380 .{ .mov, .fd, &.{ .ax, .moffs }, &.{ 0xa1 }, 0, .none, .none },
380 .{ .mov, .td, &.{ .moffs, .al }, &.{ 0xa2 }, 0, .none },381 .{ .mov, .fd, &.{ .eax, .moffs }, &.{ 0xa1 }, 0, .none, .none },
381 .{ .mov, .td, &.{ .moffs, .ax }, &.{ 0xa3 }, 0, .none },382 .{ .mov, .fd, &.{ .rax, .moffs }, &.{ 0xa1 }, 0, .long, .none },
382 .{ .mov, .td, &.{ .moffs, .eax }, &.{ 0xa3 }, 0, .none },383 .{ .mov, .td, &.{ .moffs, .al }, &.{ 0xa2 }, 0, .none, .none },
383 .{ .mov, .td, &.{ .moffs, .rax }, &.{ 0xa3 }, 0, .long },384 .{ .mov, .td, &.{ .moffs, .ax }, &.{ 0xa3 }, 0, .none, .none },
384 .{ .mov, .oi, &.{ .r8, .imm8 }, &.{ 0xb0 }, 0, .none },385 .{ .mov, .td, &.{ .moffs, .eax }, &.{ 0xa3 }, 0, .none, .none },
385 .{ .mov, .oi, &.{ .r8, .imm8 }, &.{ 0xb0 }, 0, .rex },386 .{ .mov, .td, &.{ .moffs, .rax }, &.{ 0xa3 }, 0, .long, .none },
386 .{ .mov, .oi, &.{ .r16, .imm16 }, &.{ 0xb8 }, 0, .none },387 .{ .mov, .oi, &.{ .r8, .imm8 }, &.{ 0xb0 }, 0, .none, .none },
387 .{ .mov, .oi, &.{ .r32, .imm32 }, &.{ 0xb8 }, 0, .none },388 .{ .mov, .oi, &.{ .r8, .imm8 }, &.{ 0xb0 }, 0, .rex, .none },
388 .{ .mov, .oi, &.{ .r64, .imm64 }, &.{ 0xb8 }, 0, .long },389 .{ .mov, .oi, &.{ .r16, .imm16 }, &.{ 0xb8 }, 0, .short, .none },
389 .{ .mov, .mi, &.{ .rm8, .imm8 }, &.{ 0xc6 }, 0, .none },390 .{ .mov, .oi, &.{ .r32, .imm32 }, &.{ 0xb8 }, 0, .none, .none },
390 .{ .mov, .mi, &.{ .rm8, .imm8 }, &.{ 0xc6 }, 0, .rex },391 .{ .mov, .oi, &.{ .r64, .imm64 }, &.{ 0xb8 }, 0, .long, .none },
391 .{ .mov, .mi, &.{ .rm16, .imm16 }, &.{ 0xc7 }, 0, .none },392 .{ .mov, .mi, &.{ .rm8, .imm8 }, &.{ 0xc6 }, 0, .none, .none },
392 .{ .mov, .mi, &.{ .rm32, .imm32 }, &.{ 0xc7 }, 0, .none },393 .{ .mov, .mi, &.{ .rm8, .imm8 }, &.{ 0xc6 }, 0, .rex, .none },
393 .{ .mov, .mi, &.{ .rm64, .imm32s }, &.{ 0xc7 }, 0, .long },394 .{ .mov, .mi, &.{ .rm16, .imm16 }, &.{ 0xc7 }, 0, .short, .none },
394395 .{ .mov, .mi, &.{ .rm32, .imm32 }, &.{ 0xc7 }, 0, .none, .none },
395 .{ .movbe, .rm, &.{ .r16, .m16 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .none },396 .{ .mov, .mi, &.{ .rm64, .imm32s }, &.{ 0xc7 }, 0, .long, .none },
396 .{ .movbe, .rm, &.{ .r32, .m32 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .none },397
397 .{ .movbe, .rm, &.{ .r64, .m64 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .long },398 .{ .movbe, .rm, &.{ .r16, .m16 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .short, .none },
398 .{ .movbe, .mr, &.{ .m16, .r16 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .none },399 .{ .movbe, .rm, &.{ .r32, .m32 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .none, .none },
399 .{ .movbe, .mr, &.{ .m32, .r32 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .none },400 .{ .movbe, .rm, &.{ .r64, .m64 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .long, .none },
400 .{ .movbe, .mr, &.{ .m64, .r64 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .long },401 .{ .movbe, .mr, &.{ .m16, .r16 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .short, .none },
401402 .{ .movbe, .mr, &.{ .m32, .r32 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .none, .none },
402 .{ .movs, .np, &.{ .m8, .m8 }, &.{ 0xa4 }, 0, .none },403 .{ .movbe, .mr, &.{ .m64, .r64 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .long, .none },
403 .{ .movs, .np, &.{ .m16, .m16 }, &.{ 0xa5 }, 0, .none },404
404 .{ .movs, .np, &.{ .m32, .m32 }, &.{ 0xa5 }, 0, .none },405 .{ .movs, .np, &.{ .m8, .m8 }, &.{ 0xa4 }, 0, .none, .none },
405 .{ .movs, .np, &.{ .m64, .m64 }, &.{ 0xa5 }, 0, .long },406 .{ .movs, .np, &.{ .m16, .m16 }, &.{ 0xa5 }, 0, .short, .none },
406407 .{ .movs, .np, &.{ .m32, .m32 }, &.{ 0xa5 }, 0, .none, .none },
407 .{ .movsb, .np, &.{}, &.{ 0xa4 }, 0, .none },408 .{ .movs, .np, &.{ .m64, .m64 }, &.{ 0xa5 }, 0, .long, .none },
408 .{ .movsw, .np, &.{}, &.{ 0xa5 }, 0, .short },409
409 .{ .movsd, .np, &.{}, &.{ 0xa5 }, 0, .none },410 .{ .movsb, .np, &.{}, &.{ 0xa4 }, 0, .none, .none },
410 .{ .movsq, .np, &.{}, &.{ 0xa5 }, 0, .long },411 .{ .movsw, .np, &.{}, &.{ 0xa5 }, 0, .short, .none },
411412 .{ .movsd, .np, &.{}, &.{ 0xa5 }, 0, .none, .none },
412 .{ .movsx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xbe }, 0, .none },413 .{ .movsq, .np, &.{}, &.{ 0xa5 }, 0, .long, .none },
413 .{ .movsx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xbe }, 0, .rex },414
414 .{ .movsx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xbe }, 0, .none },415 .{ .movsx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xbe }, 0, .short, .none },
415 .{ .movsx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xbe }, 0, .rex },416 .{ .movsx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xbe }, 0, .rex_short, .none },
416 .{ .movsx, .rm, &.{ .r64, .rm8 }, &.{ 0x0f, 0xbe }, 0, .long },417 .{ .movsx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xbe }, 0, .none, .none },
417 .{ .movsx, .rm, &.{ .r32, .rm16 }, &.{ 0x0f, 0xbf }, 0, .none },418 .{ .movsx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xbe }, 0, .rex, .none },
418 .{ .movsx, .rm, &.{ .r64, .rm16 }, &.{ 0x0f, 0xbf }, 0, .long },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
420 // This instruction is discouraged.424 // This instruction is discouraged.
421 .{ .movsxd, .rm, &.{ .r32, .rm32 }, &.{ 0x63 }, 0, .none },425 .{ .movsxd, .rm, &.{ .r32, .rm32 }, &.{ 0x63 }, 0, .none, .none },
422 .{ .movsxd, .rm, &.{ .r64, .rm32 }, &.{ 0x63 }, 0, .long },426 .{ .movsxd, .rm, &.{ .r64, .rm32 }, &.{ 0x63 }, 0, .long, .none },
423427
424 .{ .movzx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .none },428 .{ .movzx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .short, .none },
425 .{ .movzx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .none },429 .{ .movzx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .rex_short, .none },
426 .{ .movzx, .rm, &.{ .r64, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .long },430 .{ .movzx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .none, .none },
427 .{ .movzx, .rm, &.{ .r32, .rm16 }, &.{ 0x0f, 0xb7 }, 0, .none },431 .{ .movzx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .rex, .none },
428 .{ .movzx, .rm, &.{ .r64, .rm16 }, &.{ 0x0f, 0xb7 }, 0, .long },432 .{ .movzx, .rm, &.{ .r64, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .long, .none },
429433 .{ .movzx, .rm, &.{ .r32, .rm16 }, &.{ 0x0f, 0xb7 }, 0, .none, .none },
430 .{ .mul, .m, &.{ .rm8 }, &.{ 0xf6 }, 4, .none },434 .{ .movzx, .rm, &.{ .r32, .rm16 }, &.{ 0x0f, 0xb7 }, 0, .rex, .none },
431 .{ .mul, .m, &.{ .rm8 }, &.{ 0xf6 }, 4, .rex },435 .{ .movzx, .rm, &.{ .r64, .rm16 }, &.{ 0x0f, 0xb7 }, 0, .long, .none },
432 .{ .mul, .m, &.{ .rm16 }, &.{ 0xf7 }, 4, .none },436
433 .{ .mul, .m, &.{ .rm32 }, &.{ 0xf7 }, 4, .none },437 .{ .mul, .m, &.{ .rm8 }, &.{ 0xf6 }, 4, .none, .none },
434 .{ .mul, .m, &.{ .rm64 }, &.{ 0xf7 }, 4, .long },438 .{ .mul, .m, &.{ .rm8 }, &.{ 0xf6 }, 4, .rex, .none },
435439 .{ .mul, .m, &.{ .rm16 }, &.{ 0xf7 }, 4, .short, .none },
436 .{ .neg, .m, &.{ .rm8 }, &.{ 0xf6 }, 3, .none },440 .{ .mul, .m, &.{ .rm32 }, &.{ 0xf7 }, 4, .none, .none },
437 .{ .neg, .m, &.{ .rm8 }, &.{ 0xf6 }, 3, .rex },441 .{ .mul, .m, &.{ .rm64 }, &.{ 0xf7 }, 4, .long, .none },
438 .{ .neg, .m, &.{ .rm16 }, &.{ 0xf7 }, 3, .none },442
439 .{ .neg, .m, &.{ .rm32 }, &.{ 0xf7 }, 3, .none },443 .{ .neg, .m, &.{ .rm8 }, &.{ 0xf6 }, 3, .none, .none },
440 .{ .neg, .m, &.{ .rm64 }, &.{ 0xf7 }, 3, .long },444 .{ .neg, .m, &.{ .rm8 }, &.{ 0xf6 }, 3, .rex, .none },
441445 .{ .neg, .m, &.{ .rm16 }, &.{ 0xf7 }, 3, .short, .none },
442 .{ .nop, .np, &.{}, &.{ 0x90 }, 0, .none },446 .{ .neg, .m, &.{ .rm32 }, &.{ 0xf7 }, 3, .none, .none },
443447 .{ .neg, .m, &.{ .rm64 }, &.{ 0xf7 }, 3, .long, .none },
444 .{ .not, .m, &.{ .rm8 }, &.{ 0xf6 }, 2, .none },448
445 .{ .not, .m, &.{ .rm8 }, &.{ 0xf6 }, 2, .rex },449 .{ .nop, .np, &.{}, &.{ 0x90 }, 0, .none, .none },
446 .{ .not, .m, &.{ .rm16 }, &.{ 0xf7 }, 2, .none },450
447 .{ .not, .m, &.{ .rm32 }, &.{ 0xf7 }, 2, .none },451 .{ .not, .m, &.{ .rm8 }, &.{ 0xf6 }, 2, .none, .none },
448 .{ .not, .m, &.{ .rm64 }, &.{ 0xf7 }, 2, .long },452 .{ .not, .m, &.{ .rm8 }, &.{ 0xf6 }, 2, .rex, .none },
449453 .{ .not, .m, &.{ .rm16 }, &.{ 0xf7 }, 2, .short, .none },
450 .{ .@"or", .zi, &.{ .al, .imm8 }, &.{ 0x0c }, 0, .none },454 .{ .not, .m, &.{ .rm32 }, &.{ 0xf7 }, 2, .none, .none },
451 .{ .@"or", .zi, &.{ .ax, .imm16 }, &.{ 0x0d }, 0, .none },455 .{ .not, .m, &.{ .rm64 }, &.{ 0xf7 }, 2, .long, .none },
452 .{ .@"or", .zi, &.{ .eax, .imm32 }, &.{ 0x0d }, 0, .none },456
453 .{ .@"or", .zi, &.{ .rax, .imm32s }, &.{ 0x0d }, 0, .long },457 .{ .@"or", .zi, &.{ .al, .imm8 }, &.{ 0x0c }, 0, .none, .none },
454 .{ .@"or", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 1, .none },458 .{ .@"or", .zi, &.{ .ax, .imm16 }, &.{ 0x0d }, 0, .short, .none },
455 .{ .@"or", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 1, .rex },459 .{ .@"or", .zi, &.{ .eax, .imm32 }, &.{ 0x0d }, 0, .none, .none },
456 .{ .@"or", .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 1, .none },460 .{ .@"or", .zi, &.{ .rax, .imm32s }, &.{ 0x0d }, 0, .long, .none },
457 .{ .@"or", .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 1, .none },461 .{ .@"or", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 1, .none, .none },
458 .{ .@"or", .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 1, .long },462 .{ .@"or", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 1, .rex, .none },
459 .{ .@"or", .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 1, .none },463 .{ .@"or", .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 1, .short, .none },
460 .{ .@"or", .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 1, .none },464 .{ .@"or", .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 1, .none, .none },
461 .{ .@"or", .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 1, .long },465 .{ .@"or", .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 1, .long, .none },
462 .{ .@"or", .mr, &.{ .rm8, .r8 }, &.{ 0x08 }, 0, .none },466 .{ .@"or", .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 1, .short, .none },
463 .{ .@"or", .mr, &.{ .rm8, .r8 }, &.{ 0x08 }, 0, .rex },467 .{ .@"or", .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 1, .none, .none },
464 .{ .@"or", .mr, &.{ .rm16, .r16 }, &.{ 0x09 }, 0, .none },468 .{ .@"or", .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 1, .long, .none },
465 .{ .@"or", .mr, &.{ .rm32, .r32 }, &.{ 0x09 }, 0, .none },469 .{ .@"or", .mr, &.{ .rm8, .r8 }, &.{ 0x08 }, 0, .none, .none },
466 .{ .@"or", .mr, &.{ .rm64, .r64 }, &.{ 0x09 }, 0, .long },470 .{ .@"or", .mr, &.{ .rm8, .r8 }, &.{ 0x08 }, 0, .rex, .none },
467 .{ .@"or", .rm, &.{ .r8, .rm8 }, &.{ 0x0a }, 0, .none },471 .{ .@"or", .mr, &.{ .rm16, .r16 }, &.{ 0x09 }, 0, .short, .none },
468 .{ .@"or", .rm, &.{ .r8, .rm8 }, &.{ 0x0a }, 0, .rex },472 .{ .@"or", .mr, &.{ .rm32, .r32 }, &.{ 0x09 }, 0, .none, .none },
469 .{ .@"or", .rm, &.{ .r16, .rm16 }, &.{ 0x0b }, 0, .none },473 .{ .@"or", .mr, &.{ .rm64, .r64 }, &.{ 0x09 }, 0, .long, .none },
470 .{ .@"or", .rm, &.{ .r32, .rm32 }, &.{ 0x0b }, 0, .none },474 .{ .@"or", .rm, &.{ .r8, .rm8 }, &.{ 0x0a }, 0, .none, .none },
471 .{ .@"or", .rm, &.{ .r64, .rm64 }, &.{ 0x0b }, 0, .long },475 .{ .@"or", .rm, &.{ .r8, .rm8 }, &.{ 0x0a }, 0, .rex, .none },
472476 .{ .@"or", .rm, &.{ .r16, .rm16 }, &.{ 0x0b }, 0, .short, .none },
473 .{ .pop, .o, &.{ .r16 }, &.{ 0x58 }, 0, .none },477 .{ .@"or", .rm, &.{ .r32, .rm32 }, &.{ 0x0b }, 0, .none, .none },
474 .{ .pop, .o, &.{ .r64 }, &.{ 0x58 }, 0, .none },478 .{ .@"or", .rm, &.{ .r64, .rm64 }, &.{ 0x0b }, 0, .long, .none },
475 .{ .pop, .m, &.{ .rm16 }, &.{ 0x8f }, 0, .none },479
476 .{ .pop, .m, &.{ .rm64 }, &.{ 0x8f }, 0, .none },480 .{ .pop, .o, &.{ .r16 }, &.{ 0x58 }, 0, .short, .none },
477481 .{ .pop, .o, &.{ .r64 }, &.{ 0x58 }, 0, .none, .none },
478 .{ .popcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none },482 .{ .pop, .m, &.{ .rm16 }, &.{ 0x8f }, 0, .short, .none },
479 .{ .popcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none },483 .{ .pop, .m, &.{ .rm64 }, &.{ 0x8f }, 0, .none, .none },
480 .{ .popcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .long },484
481485 .{ .popcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .short, .none },
482 .{ .push, .o, &.{ .r16 }, &.{ 0x50 }, 0, .none },486 .{ .popcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none, .none },
483 .{ .push, .o, &.{ .r64 }, &.{ 0x50 }, 0, .none },487 .{ .popcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .long, .none },
484 .{ .push, .m, &.{ .rm16 }, &.{ 0xff }, 6, .none },488
485 .{ .push, .m, &.{ .rm64 }, &.{ 0xff }, 6, .none },489 .{ .push, .o, &.{ .r16 }, &.{ 0x50 }, 0, .short, .none },
486 .{ .push, .i, &.{ .imm8 }, &.{ 0x6a }, 0, .none },490 .{ .push, .o, &.{ .r64 }, &.{ 0x50 }, 0, .none, .none },
487 .{ .push, .i, &.{ .imm16 }, &.{ 0x68 }, 0, .none },491 .{ .push, .m, &.{ .rm16 }, &.{ 0xff }, 6, .short, .none },
488 .{ .push, .i, &.{ .imm32 }, &.{ 0x68 }, 0, .none },492 .{ .push, .m, &.{ .rm64 }, &.{ 0xff }, 6, .none, .none },
489493 .{ .push, .i, &.{ .imm8 }, &.{ 0x6a }, 0, .none, .none },
490 .{ .ret, .np, &.{}, &.{ 0xc3 }, 0, .none },494 .{ .push, .i, &.{ .imm16 }, &.{ 0x68 }, 0, .short, .none },
491495 .{ .push, .i, &.{ .imm32 }, &.{ 0x68 }, 0, .none, .none },
492 .{ .rcl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 2, .none },496
493 .{ .rcl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 2, .rex },497 .{ .ret, .np, &.{}, &.{ 0xc3 }, 0, .none, .none },
494 .{ .rcl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 2, .none },498
495 .{ .rcl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 2, .rex },499 .{ .rcl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 2, .none, .none },
496 .{ .rcl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 2, .none },500 .{ .rcl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 2, .rex, .none },
497 .{ .rcl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 2, .rex },501 .{ .rcl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 2, .none, .none },
498 .{ .rcl, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 2, .none },502 .{ .rcl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 2, .rex, .none },
499 .{ .rcl, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 2, .none },503 .{ .rcl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 2, .none, .none },
500 .{ .rcl, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 2, .none },504 .{ .rcl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 2, .rex, .none },
501 .{ .rcl, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 2, .none },505 .{ .rcl, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 2, .short, .none },
502 .{ .rcl, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 2, .long },506 .{ .rcl, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 2, .short, .none },
503 .{ .rcl, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 2, .none },507 .{ .rcl, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 2, .short, .none },
504 .{ .rcl, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 2, .long },508 .{ .rcl, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 2, .none, .none },
505 .{ .rcl, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 2, .none },509 .{ .rcl, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 2, .long, .none },
506 .{ .rcl, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 2, .long },510 .{ .rcl, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 2, .none, .none },
507511 .{ .rcl, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 2, .long, .none },
508 .{ .rcr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 3, .none },512 .{ .rcl, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 2, .none, .none },
509 .{ .rcr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 3, .rex },513 .{ .rcl, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 2, .long, .none },
510 .{ .rcr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 3, .none },514
511 .{ .rcr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 3, .rex },515 .{ .rcr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 3, .none, .none },
512 .{ .rcr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 3, .none },516 .{ .rcr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 3, .rex, .none },
513 .{ .rcr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 3, .rex },517 .{ .rcr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 3, .none, .none },
514 .{ .rcr, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 3, .none },518 .{ .rcr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 3, .rex, .none },
515 .{ .rcr, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 3, .none },519 .{ .rcr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 3, .none, .none },
516 .{ .rcr, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 3, .none },520 .{ .rcr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 3, .rex, .none },
517 .{ .rcr, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 3, .none },521 .{ .rcr, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 3, .short, .none },
518 .{ .rcr, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 3, .long },522 .{ .rcr, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 3, .short, .none },
519 .{ .rcr, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 3, .none },523 .{ .rcr, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 3, .short, .none },
520 .{ .rcr, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 3, .long },524 .{ .rcr, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 3, .none, .none },
521 .{ .rcr, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 3, .none },525 .{ .rcr, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 3, .long, .none },
522 .{ .rcr, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 3, .long },526 .{ .rcr, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 3, .none, .none },
523527 .{ .rcr, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 3, .long, .none },
524 .{ .rol, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 0, .none },528 .{ .rcr, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 3, .none, .none },
525 .{ .rol, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 0, .rex },529 .{ .rcr, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 3, .long, .none },
526 .{ .rol, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 0, .none },530
527 .{ .rol, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 0, .rex },531 .{ .rol, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 0, .none, .none },
528 .{ .rol, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 0, .none },532 .{ .rol, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 0, .rex, .none },
529 .{ .rol, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 0, .rex },533 .{ .rol, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 0, .none, .none },
530 .{ .rol, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 0, .none },534 .{ .rol, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 0, .rex, .none },
531 .{ .rol, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 0, .none },535 .{ .rol, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 0, .none, .none },
532 .{ .rol, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 0, .none },536 .{ .rol, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 0, .rex, .none },
533 .{ .rol, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 0, .none },537 .{ .rol, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 0, .short, .none },
534 .{ .rol, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 0, .long },538 .{ .rol, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 0, .short, .none },
535 .{ .rol, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 0, .none },539 .{ .rol, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 0, .short, .none },
536 .{ .rol, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 0, .long },540 .{ .rol, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 0, .none, .none },
537 .{ .rol, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 0, .none },541 .{ .rol, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 0, .long, .none },
538 .{ .rol, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 0, .long },542 .{ .rol, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 0, .none, .none },
539543 .{ .rol, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 0, .long, .none },
540 .{ .ror, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 1, .none },544 .{ .rol, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 0, .none, .none },
541 .{ .ror, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 1, .rex },545 .{ .rol, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 0, .long, .none },
542 .{ .ror, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 1, .none },546
543 .{ .ror, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 1, .rex },547 .{ .ror, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 1, .none, .none },
544 .{ .ror, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 1, .none },548 .{ .ror, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 1, .rex, .none },
545 .{ .ror, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 1, .rex },549 .{ .ror, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 1, .none, .none },
546 .{ .ror, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 1, .none },550 .{ .ror, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 1, .rex, .none },
547 .{ .ror, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 1, .none },551 .{ .ror, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 1, .none, .none },
548 .{ .ror, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 1, .none },552 .{ .ror, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 1, .rex, .none },
549 .{ .ror, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 1, .none },553 .{ .ror, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 1, .short, .none },
550 .{ .ror, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 1, .long },554 .{ .ror, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 1, .short, .none },
551 .{ .ror, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 1, .none },555 .{ .ror, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 1, .short, .none },
552 .{ .ror, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 1, .long },556 .{ .ror, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 1, .none, .none },
553 .{ .ror, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 1, .none },557 .{ .ror, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 1, .long, .none },
554 .{ .ror, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 1, .long },558 .{ .ror, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 1, .none, .none },
555559 .{ .ror, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 1, .long, .none },
556 .{ .sal, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .none },560 .{ .ror, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 1, .none, .none },
557 .{ .sal, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .rex },561 .{ .ror, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 1, .long, .none },
558 .{ .sal, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 4, .none },562
559 .{ .sal, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 4, .none },563 .{ .sal, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .none, .none },
560 .{ .sal, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 4, .long },564 .{ .sal, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .rex, .none },
561 .{ .sal, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .none },565 .{ .sal, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 4, .short, .none },
562 .{ .sal, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .rex },566 .{ .sal, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 4, .none, .none },
563 .{ .sal, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 4, .none },567 .{ .sal, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 4, .long, .none },
564 .{ .sal, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 4, .none },568 .{ .sal, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .none, .none },
565 .{ .sal, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 4, .long },569 .{ .sal, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .rex, .none },
566 .{ .sal, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .none },570 .{ .sal, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 4, .short, .none },
567 .{ .sal, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .rex },571 .{ .sal, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 4, .none, .none },
568 .{ .sal, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 4, .none },572 .{ .sal, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 4, .long, .none },
569 .{ .sal, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 4, .none },573 .{ .sal, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .none, .none },
570 .{ .sal, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 4, .long },574 .{ .sal, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .rex, .none },
571575 .{ .sal, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 4, .short, .none },
572 .{ .sar, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 7, .none },576 .{ .sal, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 4, .none, .none },
573 .{ .sar, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 7, .rex },577 .{ .sal, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 4, .long, .none },
574 .{ .sar, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 7, .none },578
575 .{ .sar, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 7, .none },579 .{ .sar, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 7, .none, .none },
576 .{ .sar, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 7, .long },580 .{ .sar, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 7, .rex, .none },
577 .{ .sar, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 7, .none },581 .{ .sar, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 7, .short, .none },
578 .{ .sar, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 7, .rex },582 .{ .sar, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 7, .none, .none },
579 .{ .sar, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 7, .none },583 .{ .sar, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 7, .long, .none },
580 .{ .sar, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 7, .none },584 .{ .sar, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 7, .none, .none },
581 .{ .sar, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 7, .long },585 .{ .sar, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 7, .rex, .none },
582 .{ .sar, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 7, .none },586 .{ .sar, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 7, .short, .none },
583 .{ .sar, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 7, .rex },587 .{ .sar, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 7, .none, .none },
584 .{ .sar, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 7, .none },588 .{ .sar, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 7, .long, .none },
585 .{ .sar, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 7, .none },589 .{ .sar, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 7, .none, .none },
586 .{ .sar, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 7, .long },590 .{ .sar, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 7, .rex, .none },
587591 .{ .sar, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 7, .short, .none },
588 .{ .sbb, .zi, &.{ .al, .imm8 }, &.{ 0x1c }, 0, .none },592 .{ .sar, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 7, .none, .none },
589 .{ .sbb, .zi, &.{ .ax, .imm16 }, &.{ 0x1d }, 0, .none },593 .{ .sar, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 7, .long, .none },
590 .{ .sbb, .zi, &.{ .eax, .imm32 }, &.{ 0x1d }, 0, .none },594
591 .{ .sbb, .zi, &.{ .rax, .imm32s }, &.{ 0x1d }, 0, .long },595 .{ .sbb, .zi, &.{ .al, .imm8 }, &.{ 0x1c }, 0, .none, .none },
592 .{ .sbb, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 3, .none },596 .{ .sbb, .zi, &.{ .ax, .imm16 }, &.{ 0x1d }, 0, .short, .none },
593 .{ .sbb, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 3, .rex },597 .{ .sbb, .zi, &.{ .eax, .imm32 }, &.{ 0x1d }, 0, .none, .none },
594 .{ .sbb, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 3, .none },598 .{ .sbb, .zi, &.{ .rax, .imm32s }, &.{ 0x1d }, 0, .long, .none },
595 .{ .sbb, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 3, .none },599 .{ .sbb, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 3, .none, .none },
596 .{ .sbb, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 3, .long },600 .{ .sbb, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 3, .rex, .none },
597 .{ .sbb, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 3, .none },601 .{ .sbb, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 3, .short, .none },
598 .{ .sbb, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 3, .none },602 .{ .sbb, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 3, .none, .none },
599 .{ .sbb, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 3, .long },603 .{ .sbb, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 3, .long, .none },
600 .{ .sbb, .mr, &.{ .rm8, .r8 }, &.{ 0x18 }, 0, .none },604 .{ .sbb, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 3, .short, .none },
601 .{ .sbb, .mr, &.{ .rm8, .r8 }, &.{ 0x18 }, 0, .rex },605 .{ .sbb, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 3, .none, .none },
602 .{ .sbb, .mr, &.{ .rm16, .r16 }, &.{ 0x19 }, 0, .none },606 .{ .sbb, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 3, .long, .none },
603 .{ .sbb, .mr, &.{ .rm32, .r32 }, &.{ 0x19 }, 0, .none },607 .{ .sbb, .mr, &.{ .rm8, .r8 }, &.{ 0x18 }, 0, .none, .none },
604 .{ .sbb, .mr, &.{ .rm64, .r64 }, &.{ 0x19 }, 0, .long },608 .{ .sbb, .mr, &.{ .rm8, .r8 }, &.{ 0x18 }, 0, .rex, .none },
605 .{ .sbb, .rm, &.{ .r8, .rm8 }, &.{ 0x1a }, 0, .none },609 .{ .sbb, .mr, &.{ .rm16, .r16 }, &.{ 0x19 }, 0, .short, .none },
606 .{ .sbb, .rm, &.{ .r8, .rm8 }, &.{ 0x1a }, 0, .rex },610 .{ .sbb, .mr, &.{ .rm32, .r32 }, &.{ 0x19 }, 0, .none, .none },
607 .{ .sbb, .rm, &.{ .r16, .rm16 }, &.{ 0x1b }, 0, .none },611 .{ .sbb, .mr, &.{ .rm64, .r64 }, &.{ 0x19 }, 0, .long, .none },
608 .{ .sbb, .rm, &.{ .r32, .rm32 }, &.{ 0x1b }, 0, .none },612 .{ .sbb, .rm, &.{ .r8, .rm8 }, &.{ 0x1a }, 0, .none, .none },
609 .{ .sbb, .rm, &.{ .r64, .rm64 }, &.{ 0x1b }, 0, .long },613 .{ .sbb, .rm, &.{ .r8, .rm8 }, &.{ 0x1a }, 0, .rex, .none },
610614 .{ .sbb, .rm, &.{ .r16, .rm16 }, &.{ 0x1b }, 0, .short, .none },
611 .{ .scas, .np, &.{ .m8 }, &.{ 0xae }, 0, .none },615 .{ .sbb, .rm, &.{ .r32, .rm32 }, &.{ 0x1b }, 0, .none, .none },
612 .{ .scas, .np, &.{ .m16 }, &.{ 0xaf }, 0, .none },616 .{ .sbb, .rm, &.{ .r64, .rm64 }, &.{ 0x1b }, 0, .long, .none },
613 .{ .scas, .np, &.{ .m32 }, &.{ 0xaf }, 0, .none },617
614 .{ .scas, .np, &.{ .m64 }, &.{ 0xaf }, 0, .long },618 .{ .scas, .np, &.{ .m8 }, &.{ 0xae }, 0, .none, .none },
615619 .{ .scas, .np, &.{ .m16 }, &.{ 0xaf }, 0, .short, .none },
616 .{ .scasb, .np, &.{}, &.{ 0xae }, 0, .none },620 .{ .scas, .np, &.{ .m32 }, &.{ 0xaf }, 0, .none, .none },
617 .{ .scasw, .np, &.{}, &.{ 0xaf }, 0, .short },621 .{ .scas, .np, &.{ .m64 }, &.{ 0xaf }, 0, .long, .none },
618 .{ .scasd, .np, &.{}, &.{ 0xaf }, 0, .none },622
619 .{ .scasq, .np, &.{}, &.{ 0xaf }, 0, .long },623 .{ .scasb, .np, &.{}, &.{ 0xae }, 0, .none, .none },
620624 .{ .scasw, .np, &.{}, &.{ 0xaf }, 0, .short, .none },
621 .{ .seta, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .none },625 .{ .scasd, .np, &.{}, &.{ 0xaf }, 0, .none, .none },
622 .{ .seta, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .rex },626 .{ .scasq, .np, &.{}, &.{ 0xaf }, 0, .long, .none },
623 .{ .setae, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none },627
624 .{ .setae, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex },628 .{ .seta, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .none, .none },
625 .{ .setb, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none },629 .{ .seta, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .rex, .none },
626 .{ .setb, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex },630 .{ .setae, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none, .none },
627 .{ .setbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .none },631 .{ .setae, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex, .none },
628 .{ .setbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .rex },632 .{ .setb, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none, .none },
629 .{ .setc, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none },633 .{ .setb, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex, .none },
630 .{ .setc, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex },634 .{ .setbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .none, .none },
631 .{ .sete, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .none },635 .{ .setbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .rex, .none },
632 .{ .sete, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .rex },636 .{ .setc, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none, .none },
633 .{ .setg, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .none },637 .{ .setc, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex, .none },
634 .{ .setg, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .rex },638 .{ .sete, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .none, .none },
635 .{ .setge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .none },639 .{ .sete, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .rex, .none },
636 .{ .setge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .rex },640 .{ .setg, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .none, .none },
637 .{ .setl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .none },641 .{ .setg, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .rex, .none },
638 .{ .setl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .rex },642 .{ .setge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .none, .none },
639 .{ .setle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .none },643 .{ .setge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .rex, .none },
640 .{ .setle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .rex },644 .{ .setl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .none, .none },
641 .{ .setna, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .none },645 .{ .setl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .rex, .none },
642 .{ .setna, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .rex },646 .{ .setle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .none, .none },
643 .{ .setnae, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none },647 .{ .setle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .rex, .none },
644 .{ .setnae, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex },648 .{ .setna, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .none, .none },
645 .{ .setnb, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none },649 .{ .setna, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .rex, .none },
646 .{ .setnb, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex },650 .{ .setnae, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none, .none },
647 .{ .setnbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .none },651 .{ .setnae, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex, .none },
648 .{ .setnbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .rex },652 .{ .setnb, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none, .none },
649 .{ .setnc, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none },653 .{ .setnb, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex, .none },
650 .{ .setnc, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex },654 .{ .setnbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .none, .none },
651 .{ .setne, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .none },655 .{ .setnbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .rex, .none },
652 .{ .setne, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .rex },656 .{ .setnc, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none, .none },
653 .{ .setng, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .none },657 .{ .setnc, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex, .none },
654 .{ .setng, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .rex },658 .{ .setne, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .none, .none },
655 .{ .setnge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .none },659 .{ .setne, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .rex, .none },
656 .{ .setnge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .rex },660 .{ .setng, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .none, .none },
657 .{ .setnl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .none },661 .{ .setng, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .rex, .none },
658 .{ .setnl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .rex },662 .{ .setnge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .none, .none },
659 .{ .setnle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .none },663 .{ .setnge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .rex, .none },
660 .{ .setnle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .rex },664 .{ .setnl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .none, .none },
661 .{ .setno, .m, &.{ .rm8 }, &.{ 0x0f, 0x91 }, 0, .none },665 .{ .setnl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .rex, .none },
662 .{ .setno, .m, &.{ .rm8 }, &.{ 0x0f, 0x91 }, 0, .rex },666 .{ .setnle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .none, .none },
663 .{ .setnp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .none },667 .{ .setnle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .rex, .none },
664 .{ .setnp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .rex },668 .{ .setno, .m, &.{ .rm8 }, &.{ 0x0f, 0x91 }, 0, .none, .none },
665 .{ .setns, .m, &.{ .rm8 }, &.{ 0x0f, 0x99 }, 0, .none },669 .{ .setno, .m, &.{ .rm8 }, &.{ 0x0f, 0x91 }, 0, .rex, .none },
666 .{ .setns, .m, &.{ .rm8 }, &.{ 0x0f, 0x99 }, 0, .rex },670 .{ .setnp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .none, .none },
667 .{ .setnz, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .none },671 .{ .setnp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .rex, .none },
668 .{ .setnz, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .rex },672 .{ .setns, .m, &.{ .rm8 }, &.{ 0x0f, 0x99 }, 0, .none, .none },
669 .{ .seto, .m, &.{ .rm8 }, &.{ 0x0f, 0x90 }, 0, .none },673 .{ .setns, .m, &.{ .rm8 }, &.{ 0x0f, 0x99 }, 0, .rex, .none },
670 .{ .seto, .m, &.{ .rm8 }, &.{ 0x0f, 0x90 }, 0, .rex },674 .{ .setnz, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .none, .none },
671 .{ .setp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .none },675 .{ .setnz, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .rex, .none },
672 .{ .setp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .rex },676 .{ .seto, .m, &.{ .rm8 }, &.{ 0x0f, 0x90 }, 0, .none, .none },
673 .{ .setpe, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .none },677 .{ .seto, .m, &.{ .rm8 }, &.{ 0x0f, 0x90 }, 0, .rex, .none },
674 .{ .setpe, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .rex },678 .{ .setp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .none, .none },
675 .{ .setpo, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .none },679 .{ .setp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .rex, .none },
676 .{ .setpo, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .rex },680 .{ .setpe, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .none, .none },
677 .{ .sets, .m, &.{ .rm8 }, &.{ 0x0f, 0x98 }, 0, .none },681 .{ .setpe, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .rex, .none },
678 .{ .sets, .m, &.{ .rm8 }, &.{ 0x0f, 0x98 }, 0, .rex },682 .{ .setpo, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .none, .none },
679 .{ .setz, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .none },683 .{ .setpo, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .rex, .none },
680 .{ .setz, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .rex },684 .{ .sets, .m, &.{ .rm8 }, &.{ 0x0f, 0x98 }, 0, .none, .none },
681685 .{ .sets, .m, &.{ .rm8 }, &.{ 0x0f, 0x98 }, 0, .rex, .none },
682 .{ .sfence, .np, &.{}, &.{ 0x0f, 0xae, 0xf8 }, 0, .none },686 .{ .setz, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .none, .none },
683687 .{ .setz, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .rex, .none },
684 .{ .shl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .none },688
685 .{ .shl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .rex },689 .{ .sfence, .np, &.{}, &.{ 0x0f, 0xae, 0xf8 }, 0, .none, .none },
686 .{ .shl, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 4, .none },690
687 .{ .shl, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 4, .none },691 .{ .shl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .none, .none },
688 .{ .shl, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 4, .long },692 .{ .shl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .rex, .none },
689 .{ .shl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .none },693 .{ .shl, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 4, .short, .none },
690 .{ .shl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .rex },694 .{ .shl, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 4, .none, .none },
691 .{ .shl, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 4, .none },695 .{ .shl, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 4, .long, .none },
692 .{ .shl, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 4, .none },696 .{ .shl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .none, .none },
693 .{ .shl, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 4, .long },697 .{ .shl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .rex, .none },
694 .{ .shl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .none },698 .{ .shl, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 4, .short, .none },
695 .{ .shl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .rex },699 .{ .shl, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 4, .none, .none },
696 .{ .shl, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 4, .none },700 .{ .shl, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 4, .long, .none },
697 .{ .shl, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 4, .none },701 .{ .shl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .none, .none },
698 .{ .shl, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 4, .long },702 .{ .shl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .rex, .none },
699703 .{ .shl, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 4, .short, .none },
700 .{ .shld, .mri, &.{ .rm16, .r16, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .none },704 .{ .shl, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 4, .none, .none },
701 .{ .shld, .mrc, &.{ .rm16, .r16, .cl }, &.{ 0x0f, 0xa5 }, 0, .none },705 .{ .shl, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 4, .long, .none },
702 .{ .shld, .mri, &.{ .rm32, .r32, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .none },706
703 .{ .shld, .mri, &.{ .rm64, .r64, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .long },707 .{ .shld, .mri, &.{ .rm16, .r16, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .short, .none },
704 .{ .shld, .mrc, &.{ .rm32, .r32, .cl }, &.{ 0x0f, 0xa5 }, 0, .none },708 .{ .shld, .mrc, &.{ .rm16, .r16, .cl }, &.{ 0x0f, 0xa5 }, 0, .short, .none },
705 .{ .shld, .mrc, &.{ .rm64, .r64, .cl }, &.{ 0x0f, 0xa5 }, 0, .long },709 .{ .shld, .mri, &.{ .rm32, .r32, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .none, .none },
706710 .{ .shld, .mri, &.{ .rm64, .r64, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .long, .none },
707 .{ .shr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 5, .none },711 .{ .shld, .mrc, &.{ .rm32, .r32, .cl }, &.{ 0x0f, 0xa5 }, 0, .none, .none },
708 .{ .shr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 5, .rex },712 .{ .shld, .mrc, &.{ .rm64, .r64, .cl }, &.{ 0x0f, 0xa5 }, 0, .long, .none },
709 .{ .shr, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 5, .none },713
710 .{ .shr, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 5, .none },714 .{ .shr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 5, .none, .none },
711 .{ .shr, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 5, .long },715 .{ .shr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 5, .rex, .none },
712 .{ .shr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 5, .none },716 .{ .shr, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 5, .short, .none },
713 .{ .shr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 5, .rex },717 .{ .shr, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 5, .none, .none },
714 .{ .shr, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 5, .none },718 .{ .shr, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 5, .long, .none },
715 .{ .shr, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 5, .none },719 .{ .shr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 5, .none, .none },
716 .{ .shr, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 5, .long },720 .{ .shr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 5, .rex, .none },
717 .{ .shr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 5, .none },721 .{ .shr, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 5, .short, .none },
718 .{ .shr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 5, .rex },722 .{ .shr, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 5, .none, .none },
719 .{ .shr, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 5, .none },723 .{ .shr, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 5, .long, .none },
720 .{ .shr, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 5, .none },724 .{ .shr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 5, .none, .none },
721 .{ .shr, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 5, .long },725 .{ .shr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 5, .rex, .none },
722726 .{ .shr, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 5, .short, .none },
723 .{ .shrd, .mri, &.{ .rm16, .r16, .imm8 }, &.{ 0x0f, 0xac }, 0, .none },727 .{ .shr, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 5, .none, .none },
724 .{ .shrd, .mrc, &.{ .rm16, .r16, .cl }, &.{ 0x0f, 0xad }, 0, .none },728 .{ .shr, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 5, .long, .none },
725 .{ .shrd, .mri, &.{ .rm32, .r32, .imm8 }, &.{ 0x0f, 0xac }, 0, .none },729
726 .{ .shrd, .mri, &.{ .rm64, .r64, .imm8 }, &.{ 0x0f, 0xac }, 0, .long },730 .{ .shrd, .mri, &.{ .rm16, .r16, .imm8 }, &.{ 0x0f, 0xac }, 0, .short, .none },
727 .{ .shrd, .mrc, &.{ .rm32, .r32, .cl }, &.{ 0x0f, 0xad }, 0, .none },731 .{ .shrd, .mrc, &.{ .rm16, .r16, .cl }, &.{ 0x0f, 0xad }, 0, .short, .none },
728 .{ .shrd, .mrc, &.{ .rm64, .r64, .cl }, &.{ 0x0f, 0xad }, 0, .long },732 .{ .shrd, .mri, &.{ .rm32, .r32, .imm8 }, &.{ 0x0f, 0xac }, 0, .none, .none },
729733 .{ .shrd, .mri, &.{ .rm64, .r64, .imm8 }, &.{ 0x0f, 0xac }, 0, .long, .none },
730 .{ .stos, .np, &.{ .m8 }, &.{ 0xaa }, 0, .none },734 .{ .shrd, .mrc, &.{ .rm32, .r32, .cl }, &.{ 0x0f, 0xad }, 0, .none, .none },
731 .{ .stos, .np, &.{ .m16 }, &.{ 0xab }, 0, .none },735 .{ .shrd, .mrc, &.{ .rm64, .r64, .cl }, &.{ 0x0f, 0xad }, 0, .long, .none },
732 .{ .stos, .np, &.{ .m32 }, &.{ 0xab }, 0, .none },736
733 .{ .stos, .np, &.{ .m64 }, &.{ 0xab }, 0, .long },737 .{ .stos, .np, &.{ .m8 }, &.{ 0xaa }, 0, .none, .none },
734738 .{ .stos, .np, &.{ .m16 }, &.{ 0xab }, 0, .short, .none },
735 .{ .stosb, .np, &.{}, &.{ 0xaa }, 0, .none },739 .{ .stos, .np, &.{ .m32 }, &.{ 0xab }, 0, .none, .none },
736 .{ .stosw, .np, &.{}, &.{ 0xab }, 0, .short },740 .{ .stos, .np, &.{ .m64 }, &.{ 0xab }, 0, .long, .none },
737 .{ .stosd, .np, &.{}, &.{ 0xab }, 0, .none },741
738 .{ .stosq, .np, &.{}, &.{ 0xab }, 0, .long },742 .{ .stosb, .np, &.{}, &.{ 0xaa }, 0, .none, .none },
739743 .{ .stosw, .np, &.{}, &.{ 0xab }, 0, .short, .none },
740 .{ .sub, .zi, &.{ .al, .imm8 }, &.{ 0x2c }, 0, .none },744 .{ .stosd, .np, &.{}, &.{ 0xab }, 0, .none, .none },
741 .{ .sub, .zi, &.{ .ax, .imm16 }, &.{ 0x2d }, 0, .none },745 .{ .stosq, .np, &.{}, &.{ 0xab }, 0, .long, .none },
742 .{ .sub, .zi, &.{ .eax, .imm32 }, &.{ 0x2d }, 0, .none },746
743 .{ .sub, .zi, &.{ .rax, .imm32s }, &.{ 0x2d }, 0, .long },747 .{ .sub, .zi, &.{ .al, .imm8 }, &.{ 0x2c }, 0, .none, .none },
744 .{ .sub, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 5, .none },748 .{ .sub, .zi, &.{ .ax, .imm16 }, &.{ 0x2d }, 0, .short, .none },
745 .{ .sub, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 5, .rex },749 .{ .sub, .zi, &.{ .eax, .imm32 }, &.{ 0x2d }, 0, .none, .none },
746 .{ .sub, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 5, .none },750 .{ .sub, .zi, &.{ .rax, .imm32s }, &.{ 0x2d }, 0, .long, .none },
747 .{ .sub, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 5, .none },751 .{ .sub, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 5, .none, .none },
748 .{ .sub, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 5, .long },752 .{ .sub, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 5, .rex, .none },
749 .{ .sub, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 5, .none },753 .{ .sub, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 5, .short, .none },
750 .{ .sub, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 5, .none },754 .{ .sub, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 5, .none, .none },
751 .{ .sub, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 5, .long },755 .{ .sub, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 5, .long, .none },
752 .{ .sub, .mr, &.{ .rm8, .r8 }, &.{ 0x28 }, 0, .none },756 .{ .sub, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 5, .short, .none },
753 .{ .sub, .mr, &.{ .rm8, .r8 }, &.{ 0x28 }, 0, .rex },757 .{ .sub, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 5, .none, .none },
754 .{ .sub, .mr, &.{ .rm16, .r16 }, &.{ 0x29 }, 0, .none },758 .{ .sub, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 5, .long, .none },
755 .{ .sub, .mr, &.{ .rm32, .r32 }, &.{ 0x29 }, 0, .none },759 .{ .sub, .mr, &.{ .rm8, .r8 }, &.{ 0x28 }, 0, .none, .none },
756 .{ .sub, .mr, &.{ .rm64, .r64 }, &.{ 0x29 }, 0, .long },760 .{ .sub, .mr, &.{ .rm8, .r8 }, &.{ 0x28 }, 0, .rex, .none },
757 .{ .sub, .rm, &.{ .r8, .rm8 }, &.{ 0x2a }, 0, .none },761 .{ .sub, .mr, &.{ .rm16, .r16 }, &.{ 0x29 }, 0, .short, .none },
758 .{ .sub, .rm, &.{ .r8, .rm8 }, &.{ 0x2a }, 0, .rex },762 .{ .sub, .mr, &.{ .rm32, .r32 }, &.{ 0x29 }, 0, .none, .none },
759 .{ .sub, .rm, &.{ .r16, .rm16 }, &.{ 0x2b }, 0, .none },763 .{ .sub, .mr, &.{ .rm64, .r64 }, &.{ 0x29 }, 0, .long, .none },
760 .{ .sub, .rm, &.{ .r32, .rm32 }, &.{ 0x2b }, 0, .none },764 .{ .sub, .rm, &.{ .r8, .rm8 }, &.{ 0x2a }, 0, .none, .none },
761 .{ .sub, .rm, &.{ .r64, .rm64 }, &.{ 0x2b }, 0, .long },765 .{ .sub, .rm, &.{ .r8, .rm8 }, &.{ 0x2a }, 0, .rex, .none },
762766 .{ .sub, .rm, &.{ .r16, .rm16 }, &.{ 0x2b }, 0, .short, .none },
763 .{ .syscall, .np, &.{}, &.{ 0x0f, 0x05 }, 0, .none }767 .{ .sub, .rm, &.{ .r32, .rm32 }, &.{ 0x2b }, 0, .none, .none },
764,768 .{ .sub, .rm, &.{ .r64, .rm64 }, &.{ 0x2b }, 0, .long, .none },
765 .{ .@"test", .zi, &.{ .al, .imm8 }, &.{ 0xa8 }, 0, .none },769
766 .{ .@"test", .zi, &.{ .ax, .imm16 }, &.{ 0xa9 }, 0, .none },770 .{ .syscall, .np, &.{}, &.{ 0x0f, 0x05 }, 0, .none, .none },
767 .{ .@"test", .zi, &.{ .eax, .imm32 }, &.{ 0xa9 }, 0, .none },771
768 .{ .@"test", .zi, &.{ .rax, .imm32s }, &.{ 0xa9 }, 0, .long },772 .{ .@"test", .zi, &.{ .al, .imm8 }, &.{ 0xa8 }, 0, .none, .none },
769 .{ .@"test", .mi, &.{ .rm8, .imm8 }, &.{ 0xf6 }, 0, .none },773 .{ .@"test", .zi, &.{ .ax, .imm16 }, &.{ 0xa9 }, 0, .short, .none },
770 .{ .@"test", .mi, &.{ .rm8, .imm8 }, &.{ 0xf6 }, 0, .rex },774 .{ .@"test", .zi, &.{ .eax, .imm32 }, &.{ 0xa9 }, 0, .none, .none },
771 .{ .@"test", .mi, &.{ .rm16, .imm16 }, &.{ 0xf7 }, 0, .none },775 .{ .@"test", .zi, &.{ .rax, .imm32s }, &.{ 0xa9 }, 0, .long, .none },
772 .{ .@"test", .mi, &.{ .rm32, .imm32 }, &.{ 0xf7 }, 0, .none },776 .{ .@"test", .mi, &.{ .rm8, .imm8 }, &.{ 0xf6 }, 0, .none, .none },
773 .{ .@"test", .mi, &.{ .rm64, .imm32s }, &.{ 0xf7 }, 0, .long },777 .{ .@"test", .mi, &.{ .rm8, .imm8 }, &.{ 0xf6 }, 0, .rex, .none },
774 .{ .@"test", .mr, &.{ .rm8, .r8 }, &.{ 0x84 }, 0, .none },778 .{ .@"test", .mi, &.{ .rm16, .imm16 }, &.{ 0xf7 }, 0, .short, .none },
775 .{ .@"test", .mr, &.{ .rm8, .r8 }, &.{ 0x84 }, 0, .rex },779 .{ .@"test", .mi, &.{ .rm32, .imm32 }, &.{ 0xf7 }, 0, .none, .none },
776 .{ .@"test", .mr, &.{ .rm16, .r16 }, &.{ 0x85 }, 0, .none },780 .{ .@"test", .mi, &.{ .rm64, .imm32s }, &.{ 0xf7 }, 0, .long, .none },
777 .{ .@"test", .mr, &.{ .rm32, .r32 }, &.{ 0x85 }, 0, .none },781 .{ .@"test", .mr, &.{ .rm8, .r8 }, &.{ 0x84 }, 0, .none, .none },
778 .{ .@"test", .mr, &.{ .rm64, .r64 }, &.{ 0x85 }, 0, .long },782 .{ .@"test", .mr, &.{ .rm8, .r8 }, &.{ 0x84 }, 0, .rex, .none },
779783 .{ .@"test", .mr, &.{ .rm16, .r16 }, &.{ 0x85 }, 0, .short, .none },
780 .{ .tzcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .none },784 .{ .@"test", .mr, &.{ .rm32, .r32 }, &.{ 0x85 }, 0, .none, .none },
781 .{ .tzcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .none },785 .{ .@"test", .mr, &.{ .rm64, .r64 }, &.{ 0x85 }, 0, .long, .none },
782 .{ .tzcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .long },786
783787 .{ .tzcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .short, .none },
784 .{ .ud2, .np, &.{}, &.{ 0x0f, 0x0b }, 0, .none },788 .{ .tzcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .none, .none },
785789 .{ .tzcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .long, .none },
786 .{ .xadd, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xc0 }, 0, .none },790
787 .{ .xadd, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xc0 }, 0, .rex },791 .{ .ud2, .np, &.{}, &.{ 0x0f, 0x0b }, 0, .none, .none },
788 .{ .xadd, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xc1 }, 0, .none },792
789 .{ .xadd, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xc1 }, 0, .none },793 .{ .xadd, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xc0 }, 0, .none, .none },
790 .{ .xadd, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xc1 }, 0, .long },794 .{ .xadd, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xc0 }, 0, .rex, .none },
791795 .{ .xadd, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xc1 }, 0, .short, .none },
792 .{ .xchg, .o, &.{ .ax, .r16 }, &.{ 0x90 }, 0, .none },796 .{ .xadd, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xc1 }, 0, .none, .none },
793 .{ .xchg, .o, &.{ .r16, .ax }, &.{ 0x90 }, 0, .none },797 .{ .xadd, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xc1 }, 0, .long, .none },
794 .{ .xchg, .o, &.{ .eax, .r32 }, &.{ 0x90 }, 0, .none },798
795 .{ .xchg, .o, &.{ .rax, .r64 }, &.{ 0x90 }, 0, .long },799 .{ .xchg, .o, &.{ .ax, .r16 }, &.{ 0x90 }, 0, .short, .none },
796 .{ .xchg, .o, &.{ .r32, .eax }, &.{ 0x90 }, 0, .none },800 .{ .xchg, .o, &.{ .r16, .ax }, &.{ 0x90 }, 0, .short, .none },
797 .{ .xchg, .o, &.{ .r64, .rax }, &.{ 0x90 }, 0, .long },801 .{ .xchg, .o, &.{ .eax, .r32 }, &.{ 0x90 }, 0, .none, .none },
798 .{ .xchg, .mr, &.{ .rm8, .r8 }, &.{ 0x86 }, 0, .none },802 .{ .xchg, .o, &.{ .rax, .r64 }, &.{ 0x90 }, 0, .long, .none },
799 .{ .xchg, .mr, &.{ .rm8, .r8 }, &.{ 0x86 }, 0, .rex },803 .{ .xchg, .o, &.{ .r32, .eax }, &.{ 0x90 }, 0, .none, .none },
800 .{ .xchg, .rm, &.{ .r8, .rm8 }, &.{ 0x86 }, 0, .none },804 .{ .xchg, .o, &.{ .r64, .rax }, &.{ 0x90 }, 0, .long, .none },
801 .{ .xchg, .rm, &.{ .r8, .rm8 }, &.{ 0x86 }, 0, .rex },805 .{ .xchg, .mr, &.{ .rm8, .r8 }, &.{ 0x86 }, 0, .none, .none },
802 .{ .xchg, .mr, &.{ .rm16, .r16 }, &.{ 0x87 }, 0, .none },806 .{ .xchg, .mr, &.{ .rm8, .r8 }, &.{ 0x86 }, 0, .rex, .none },
803 .{ .xchg, .rm, &.{ .r16, .rm16 }, &.{ 0x87 }, 0, .none },807 .{ .xchg, .rm, &.{ .r8, .rm8 }, &.{ 0x86 }, 0, .none, .none },
804 .{ .xchg, .mr, &.{ .rm32, .r32 }, &.{ 0x87 }, 0, .none },808 .{ .xchg, .rm, &.{ .r8, .rm8 }, &.{ 0x86 }, 0, .rex, .none },
805 .{ .xchg, .mr, &.{ .rm64, .r64 }, &.{ 0x87 }, 0, .long },809 .{ .xchg, .mr, &.{ .rm16, .r16 }, &.{ 0x87 }, 0, .short, .none },
806 .{ .xchg, .rm, &.{ .r32, .rm32 }, &.{ 0x87 }, 0, .none },810 .{ .xchg, .rm, &.{ .r16, .rm16 }, &.{ 0x87 }, 0, .short, .none },
807 .{ .xchg, .rm, &.{ .r64, .rm64 }, &.{ 0x87 }, 0, .long },811 .{ .xchg, .mr, &.{ .rm32, .r32 }, &.{ 0x87 }, 0, .none, .none },
808812 .{ .xchg, .mr, &.{ .rm64, .r64 }, &.{ 0x87 }, 0, .long, .none },
809 .{ .xor, .zi, &.{ .al, .imm8 }, &.{ 0x34 }, 0, .none },813 .{ .xchg, .rm, &.{ .r32, .rm32 }, &.{ 0x87 }, 0, .none, .none },
810 .{ .xor, .zi, &.{ .ax, .imm16 }, &.{ 0x35 }, 0, .none },814 .{ .xchg, .rm, &.{ .r64, .rm64 }, &.{ 0x87 }, 0, .long, .none },
811 .{ .xor, .zi, &.{ .eax, .imm32 }, &.{ 0x35 }, 0, .none },815
812 .{ .xor, .zi, &.{ .rax, .imm32s }, &.{ 0x35 }, 0, .long },816 .{ .xor, .zi, &.{ .al, .imm8 }, &.{ 0x34 }, 0, .none, .none },
813 .{ .xor, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 6, .none },817 .{ .xor, .zi, &.{ .ax, .imm16 }, &.{ 0x35 }, 0, .short, .none },
814 .{ .xor, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 6, .rex },818 .{ .xor, .zi, &.{ .eax, .imm32 }, &.{ 0x35 }, 0, .none, .none },
815 .{ .xor, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 6, .none },819 .{ .xor, .zi, &.{ .rax, .imm32s }, &.{ 0x35 }, 0, .long, .none },
816 .{ .xor, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 6, .none },820 .{ .xor, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 6, .none, .none },
817 .{ .xor, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 6, .long },821 .{ .xor, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 6, .rex, .none },
818 .{ .xor, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 6, .none },822 .{ .xor, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 6, .short, .none },
819 .{ .xor, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 6, .none },823 .{ .xor, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 6, .none, .none },
820 .{ .xor, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 6, .long },824 .{ .xor, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 6, .long, .none },
821 .{ .xor, .mr, &.{ .rm8, .r8 }, &.{ 0x30 }, 0, .none },825 .{ .xor, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 6, .short, .none },
822 .{ .xor, .mr, &.{ .rm8, .r8 }, &.{ 0x30 }, 0, .rex },826 .{ .xor, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 6, .none, .none },
823 .{ .xor, .mr, &.{ .rm16, .r16 }, &.{ 0x31 }, 0, .none },827 .{ .xor, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 6, .long, .none },
824 .{ .xor, .mr, &.{ .rm32, .r32 }, &.{ 0x31 }, 0, .none },828 .{ .xor, .mr, &.{ .rm8, .r8 }, &.{ 0x30 }, 0, .none, .none },
825 .{ .xor, .mr, &.{ .rm64, .r64 }, &.{ 0x31 }, 0, .long },829 .{ .xor, .mr, &.{ .rm8, .r8 }, &.{ 0x30 }, 0, .rex, .none },
826 .{ .xor, .rm, &.{ .r8, .rm8 }, &.{ 0x32 }, 0, .none },830 .{ .xor, .mr, &.{ .rm16, .r16 }, &.{ 0x31 }, 0, .short, .none },
827 .{ .xor, .rm, &.{ .r8, .rm8 }, &.{ 0x32 }, 0, .rex },831 .{ .xor, .mr, &.{ .rm32, .r32 }, &.{ 0x31 }, 0, .none, .none },
828 .{ .xor, .rm, &.{ .r16, .rm16 }, &.{ 0x33 }, 0, .none },832 .{ .xor, .mr, &.{ .rm64, .r64 }, &.{ 0x31 }, 0, .long, .none },
829 .{ .xor, .rm, &.{ .r32, .rm32 }, &.{ 0x33 }, 0, .none },833 .{ .xor, .rm, &.{ .r8, .rm8 }, &.{ 0x32 }, 0, .none, .none },
830 .{ .xor, .rm, &.{ .r64, .rm64 }, &.{ 0x33 }, 0, .long },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
832 // SSE839 // 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 },848 .{ .cmpss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0xf3, 0x0f, 0xc2 }, 0, .none, .sse },
842 .{ .cvtsi2ss, .rm, &.{ .xmm, .rm64 }, &.{ 0xf3, 0x0f, 0x2a }, 0, .sse_long },
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 },857 .{ .maxps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x5f }, 0, .none, .sse },
851 .{ .movaps, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x0f, 0x29 }, 0, .sse },
852858
853 .{ .movss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x10 }, 0, .sse },859 .{ .maxss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5f }, 0, .none, .sse },
854 .{ .movss, .mr, &.{ .xmm_m32, .xmm }, &.{ 0xf3, 0x0f, 0x11 }, 0, .sse },
855860
856 .{ .movups, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x10 }, 0, .sse },861 .{ .minps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x5d }, 0, .none, .sse },
857 .{ .movups, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x0f, 0x11 }, 0, .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 },870 .{ .movss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x10 }, 0, .none, .sse },
866 .{ .sqrtss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x51 }, 0, .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
872 // SSE2894 // 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 },941 .{ .mulsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x59 }, 0, .none, .sse2 },
884 .{ .cvtsi2sd, .rm, &.{ .xmm, .rm64 }, &.{ 0xf2, 0x0f, 0x2a }, 0, .sse2_long },
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 },951 .{ .pshuflw, .rmi, &.{ .xmm, .xmm_m128, .imm8 }, &.{ 0xf2, 0x0f, 0x70 }, 0, .none, .sse2 },
895 .{ .movapd, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x66, 0x0f, 0x29 }, 0, .sse2 },
896952
897 .{ .movd, .rm, &.{ .xmm, .rm32 }, &.{ 0x66, 0x0f, 0x6e }, 0, .sse2 },953 .{ .psrlw, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xd1 }, 0, .none, .sse2 },
898 .{ .movd, .mr, &.{ .rm32, .xmm }, &.{ 0x66, 0x0f, 0x7e }, 0, .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 },960 .{ .punpckhbw, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x68 }, 0, .none, .sse2 },
901 .{ .movq, .mr, &.{ .rm64, .xmm }, &.{ 0x66, 0x0f, 0x7e }, 0, .sse2_long },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 },965 .{ .punpcklbw, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x60 }, 0, .none, .sse2 },
904 .{ .movq, .mr, &.{ .xmm_m64, .xmm }, &.{ 0x66, 0x0f, 0xd6 }, 0, .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 },970 .{ .sqrtpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x51 }, 0, .none, .sse2 },
907 .{ .movupd, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x66, 0x0f, 0x11 }, 0, .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 },981 .{ .ucomisd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x2e }, 0, .none, .sse2 },
918 .{ .sqrtsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x51 }, 0, .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 },985 // SSE3
923 .{ .movsd, .mr, &.{ .xmm_m64, .xmm }, &.{ 0xf2, 0x0f, 0x11 }, 0, .sse2 },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
929 // SSE4.1992 // 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 },1216 .{ .vpunpcklbw, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x60 }, 0, .vex_256_wig, .avx2 },
933 .{ .roundsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .sse4_1 },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 },
934};1220};
935// zig fmt: on1221// zig fmt: on
src/link/Dwarf.zig+29-25
...@@ -526,7 +526,7 @@ pub const DeclState = struct {...@@ -526,7 +526,7 @@ pub const DeclState = struct {
526 .ErrorUnion => {526 .ErrorUnion => {
527 const error_ty = ty.errorUnionSet();527 const error_ty = ty.errorUnionSet();
528 const payload_ty = ty.errorUnionPayload();528 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);
530 const error_align = Type.anyerror.abiAlignment(target);530 const error_align = Type.anyerror.abiAlignment(target);
531 const abi_size = ty.abiSize(target);531 const abi_size = ty.abiSize(target);
532 const payload_off = if (error_align >= payload_align) Type.anyerror.abiSize(target) else 0;532 const payload_off = if (error_align >= payload_align) Type.anyerror.abiSize(target) else 0;
...@@ -540,31 +540,35 @@ pub const DeclState = struct {...@@ -540,31 +540,35 @@ pub const DeclState = struct {
540 const name = try ty.nameAllocArena(arena, module);540 const name = try ty.nameAllocArena(arena, module);
541 try dbg_info_buffer.writer().print("{s}\x00", .{name});541 try dbg_info_buffer.writer().print("{s}\x00", .{name});
542542
543 // DW.AT.member543 if (!payload_ty.isNoReturn()) {
544 try dbg_info_buffer.ensureUnusedCapacity(7);544 // DW.AT.member
545 dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member));545 try dbg_info_buffer.ensureUnusedCapacity(7);
546 // DW.AT.name, DW.FORM.string546 dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member));
547 dbg_info_buffer.appendSliceAssumeCapacity("value");547 // DW.AT.name, DW.FORM.string
548 dbg_info_buffer.appendAssumeCapacity(0);548 dbg_info_buffer.appendSliceAssumeCapacity("value");
549 // DW.AT.type, DW.FORM.ref4549 dbg_info_buffer.appendAssumeCapacity(0);
550 var index = dbg_info_buffer.items.len;550 // DW.AT.type, DW.FORM.ref4
551 try dbg_info_buffer.resize(index + 4);551 const index = dbg_info_buffer.items.len;
552 try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(u32, index));552 try dbg_info_buffer.resize(index + 4);
553 // DW.AT.data_member_location, DW.FORM.sdata553 try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(u32, index));
554 try leb128.writeULEB128(dbg_info_buffer.writer(), payload_off);554 // DW.AT.data_member_location, DW.FORM.sdata
555 try leb128.writeULEB128(dbg_info_buffer.writer(), payload_off);
556 }
555557
556 // DW.AT.member558 {
557 try dbg_info_buffer.ensureUnusedCapacity(5);559 // DW.AT.member
558 dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member));560 try dbg_info_buffer.ensureUnusedCapacity(5);
559 // DW.AT.name, DW.FORM.string561 dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member));
560 dbg_info_buffer.appendSliceAssumeCapacity("err");562 // DW.AT.name, DW.FORM.string
561 dbg_info_buffer.appendAssumeCapacity(0);563 dbg_info_buffer.appendSliceAssumeCapacity("err");
562 // DW.AT.type, DW.FORM.ref4564 dbg_info_buffer.appendAssumeCapacity(0);
563 index = dbg_info_buffer.items.len;565 // DW.AT.type, DW.FORM.ref4
564 try dbg_info_buffer.resize(index + 4);566 const index = dbg_info_buffer.items.len;
565 try self.addTypeRelocGlobal(atom_index, error_ty, @intCast(u32, index));567 try dbg_info_buffer.resize(index + 4);
566 // DW.AT.data_member_location, DW.FORM.sdata568 try self.addTypeRelocGlobal(atom_index, error_ty, @intCast(u32, index));
567 try leb128.writeULEB128(dbg_info_buffer.writer(), error_off);569 // DW.AT.data_member_location, DW.FORM.sdata
570 try leb128.writeULEB128(dbg_info_buffer.writer(), error_off);
571 }
568572
569 // DW.AT.structure_type delimit children573 // DW.AT.structure_type delimit children
570 try dbg_info_buffer.append(0);574 try dbg_info_buffer.append(0);
test/behavior/bugs/12891.zig-6
...@@ -29,7 +29,6 @@ test "inf >= 1" {...@@ -29,7 +29,6 @@ test "inf >= 1" {
29test "isNan(nan * 1)" {29test "isNan(nan * 1)" {
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
31 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO31 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
32 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
3332
34 const nan_times_one = comptime std.math.nan(f64) * 1;33 const nan_times_one = comptime std.math.nan(f64) * 1;
35 try std.testing.expect(std.math.isNan(nan_times_one));34 try std.testing.expect(std.math.isNan(nan_times_one));
...@@ -37,7 +36,6 @@ test "isNan(nan * 1)" {...@@ -37,7 +36,6 @@ test "isNan(nan * 1)" {
37test "runtime isNan(nan * 1)" {36test "runtime isNan(nan * 1)" {
38 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO37 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
39 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO38 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
40 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
4139
42 const nan_times_one = std.math.nan(f64) * 1;40 const nan_times_one = std.math.nan(f64) * 1;
43 try std.testing.expect(std.math.isNan(nan_times_one));41 try std.testing.expect(std.math.isNan(nan_times_one));
...@@ -45,7 +43,6 @@ test "runtime isNan(nan * 1)" {...@@ -45,7 +43,6 @@ test "runtime isNan(nan * 1)" {
45test "isNan(nan * 0)" {43test "isNan(nan * 0)" {
46 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO44 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
47 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO45 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
4946
50 const nan_times_zero = comptime std.math.nan(f64) * 0;47 const nan_times_zero = comptime std.math.nan(f64) * 0;
51 try std.testing.expect(std.math.isNan(nan_times_zero));48 try std.testing.expect(std.math.isNan(nan_times_zero));
...@@ -55,7 +52,6 @@ test "isNan(nan * 0)" {...@@ -55,7 +52,6 @@ test "isNan(nan * 0)" {
55test "isNan(inf * 0)" {52test "isNan(inf * 0)" {
56 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO53 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
57 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO54 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
58 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
5955
60 const inf_times_zero = comptime std.math.inf(f64) * 0;56 const inf_times_zero = comptime std.math.inf(f64) * 0;
61 try std.testing.expect(std.math.isNan(inf_times_zero));57 try std.testing.expect(std.math.isNan(inf_times_zero));
...@@ -65,7 +61,6 @@ test "isNan(inf * 0)" {...@@ -65,7 +61,6 @@ test "isNan(inf * 0)" {
65test "runtime isNan(nan * 0)" {61test "runtime isNan(nan * 0)" {
66 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO62 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
67 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO63 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
68 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
6964
70 const nan_times_zero = std.math.nan(f64) * 0;65 const nan_times_zero = std.math.nan(f64) * 0;
71 try std.testing.expect(std.math.isNan(nan_times_zero));66 try std.testing.expect(std.math.isNan(nan_times_zero));
...@@ -75,7 +70,6 @@ test "runtime isNan(nan * 0)" {...@@ -75,7 +70,6 @@ test "runtime isNan(nan * 0)" {
75test "runtime isNan(inf * 0)" {70test "runtime isNan(inf * 0)" {
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO71 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO72 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
78 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
7973
80 const inf_times_zero = std.math.inf(f64) * 0;74 const inf_times_zero = std.math.inf(f64) * 0;
81 try std.testing.expect(std.math.isNan(inf_times_zero));75 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 {...@@ -9,7 +9,8 @@ fn ctz(x: anytype) usize {
99
10test "fixed" {10test "fixed" {
11 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO11 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO12 if (builtin.zig_backend == .stage2_x86_64 and
13 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .bmi)) return error.SkipZigTest; // TODO
13 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO14 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO16 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" {...@@ -757,7 +757,6 @@ test "error union of noreturn used with if" {
757 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO757 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
758 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO758 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
759 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO759 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
760 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
761 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO760 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
762761
763 NoReturn.a = 64;762 NoReturn.a = 64;
...@@ -772,7 +771,6 @@ test "error union of noreturn used with try" {...@@ -772,7 +771,6 @@ test "error union of noreturn used with try" {
772 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO771 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
773 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO772 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
774 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO773 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
775 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
776 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO774 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
777775
778 NoReturn.a = 64;776 NoReturn.a = 64;
...@@ -784,7 +782,6 @@ test "error union of noreturn used with catch" {...@@ -784,7 +782,6 @@ test "error union of noreturn used with catch" {
784 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO782 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
785 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO783 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
786 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO784 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
787 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
788 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO785 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
789786
790 NoReturn.a = 64;787 NoReturn.a = 64;
test/behavior/field_parent_ptr.zig-1
...@@ -2,7 +2,6 @@ const expect = @import("std").testing.expect;...@@ -2,7 +2,6 @@ const expect = @import("std").testing.expect;
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4test "@fieldParentPtr non-first field" {4test "@fieldParentPtr non-first field" {
5 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;5 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO6 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8 try testParentFieldPtr(&foo.c);7 try testParentFieldPtr(&foo.c);
test/behavior/floatop.zig+17-14
...@@ -8,6 +8,8 @@ const has_f80_rt = switch (builtin.cpu.arch) {...@@ -8,6 +8,8 @@ const has_f80_rt = switch (builtin.cpu.arch) {
8 .x86_64, .x86 => true,8 .x86_64, .x86 => true,
9 else => false,9 else => false,
10};10};
11const no_x86_64_hardware_f16_support = builtin.zig_backend == .stage2_x86_64 and
12 !std.Target.x86.featureSetHas(builtin.cpu.features, .f16c);
1113
12const epsilon_16 = 0.001;14const epsilon_16 = 0.001;
13const epsilon = 0.000001;15const epsilon = 0.000001;
...@@ -52,7 +54,7 @@ fn testFloatComparisons() !void {...@@ -52,7 +54,7 @@ fn testFloatComparisons() !void {
52}54}
5355
54test "different sized float comparisons" {56test "different sized float comparisons" {
55 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO57 if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
56 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO58 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
57 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO59 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
58 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO60 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -134,7 +136,6 @@ fn testSqrt() !void {...@@ -134,7 +136,6 @@ fn testSqrt() !void {
134136
135test "@sqrt with vectors" {137test "@sqrt with vectors" {
136 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO138 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
137 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
138 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO139 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
139 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO140 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
140141
...@@ -152,7 +153,7 @@ fn testSqrtWithVectors() !void {...@@ -152,7 +153,7 @@ fn testSqrtWithVectors() !void {
152}153}
153154
154test "more @sqrt f16 tests" {155test "more @sqrt f16 tests" {
155 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO156 if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
156 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO157 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
157 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO158 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO159 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -202,7 +203,7 @@ fn testSqrtLegacy(comptime T: type, x: T) !void {...@@ -202,7 +203,7 @@ fn testSqrtLegacy(comptime T: type, x: T) !void {
202}203}
203204
204test "@sin" {205test "@sin" {
205 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO206 if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
206 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO207 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
207 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO208 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
208 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO209 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -241,7 +242,7 @@ fn testSinWithVectors() !void {...@@ -241,7 +242,7 @@ fn testSinWithVectors() !void {
241}242}
242243
243test "@cos" {244test "@cos" {
244 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO245 if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
245 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO246 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
246 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO247 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
247 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO248 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -280,7 +281,7 @@ fn testCosWithVectors() !void {...@@ -280,7 +281,7 @@ fn testCosWithVectors() !void {
280}281}
281282
282test "@exp" {283test "@exp" {
283 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO284 if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
284 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO285 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
285 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO286 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
286 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO287 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -318,7 +319,7 @@ fn testExpWithVectors() !void {...@@ -318,7 +319,7 @@ fn testExpWithVectors() !void {
318}319}
319320
320test "@exp2" {321test "@exp2" {
321 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO322 if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
322 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO323 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
323 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO324 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
324 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO325 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -403,7 +404,7 @@ test "@log with @vectors" {...@@ -403,7 +404,7 @@ test "@log with @vectors" {
403}404}
404405
405test "@log2" {406test "@log2" {
406 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO407 if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
407 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO408 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
408 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO409 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
409 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO410 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -445,7 +446,7 @@ fn testLog2WithVectors() !void {...@@ -445,7 +446,7 @@ fn testLog2WithVectors() !void {
445}446}
446447
447test "@log10" {448test "@log10" {
448 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO449 if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
449 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO450 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
450 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO451 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
451 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO452 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -617,7 +618,8 @@ fn testFloor() !void {...@@ -617,7 +618,8 @@ fn testFloor() !void {
617618
618test "@floor with vectors" {619test "@floor with vectors" {
619 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO620 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
620 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO621 if (builtin.zig_backend == .stage2_x86_64 and
622 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
621 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO623 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
622 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO624 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
623625
...@@ -707,7 +709,8 @@ fn testCeil() !void {...@@ -707,7 +709,8 @@ fn testCeil() !void {
707709
708test "@ceil with vectors" {710test "@ceil with vectors" {
709 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO711 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
710 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO712 if (builtin.zig_backend == .stage2_x86_64 and
713 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
711 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO714 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
712 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO715 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
713716
...@@ -797,7 +800,8 @@ fn testTrunc() !void {...@@ -797,7 +800,8 @@ fn testTrunc() !void {
797800
798test "@trunc with vectors" {801test "@trunc with vectors" {
799 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO802 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
800 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO803 if (builtin.zig_backend == .stage2_x86_64 and
804 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
801 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO805 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
802 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO806 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
803807
...@@ -878,7 +882,7 @@ fn testTruncLegacy(comptime T: type, x: T) !void {...@@ -878,7 +882,7 @@ fn testTruncLegacy(comptime T: type, x: T) !void {
878}882}
879883
880test "negation f16" {884test "negation f16" {
881 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO885 if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
882 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO886 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
883 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO887 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
884 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO888 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1037,7 +1041,6 @@ test "comptime_float zero divided by zero produces zero" {...@@ -1037,7 +1041,6 @@ test "comptime_float zero divided by zero produces zero" {
1037}1041}
10381042
1039test "nan negation f16" {1043test "nan negation f16" {
1040 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1041 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1044 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1042 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1045 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1043 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1046 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/math.zig+4-2
...@@ -77,7 +77,8 @@ fn testClz() !void {...@@ -77,7 +77,8 @@ fn testClz() !void {
77}77}
7878
79test "@clz big ints" {79test "@clz big ints" {
80 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO80 if (builtin.zig_backend == .stage2_x86_64 and
81 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .lzcnt)) return error.SkipZigTest; // TODO
81 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO82 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
82 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO83 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
83 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO84 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -398,7 +399,8 @@ fn testBinaryNot128(comptime Type: type, x: Type) !void {...@@ -398,7 +399,8 @@ fn testBinaryNot128(comptime Type: type, x: Type) !void {
398399
399test "division" {400test "division" {
400 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO401 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
401 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO402 if (builtin.zig_backend == .stage2_x86_64 and
403 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
402 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO404 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
403 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO405 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
404 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO406 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/muladd.zig+8-4
...@@ -1,8 +1,12 @@...@@ -1,8 +1,12 @@
1const std = @import("std");
1const builtin = @import("builtin");2const 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
4test "@mulAdd" {8test "@mulAdd" {
5 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO9 if (no_x86_64_hardware_fma_support) return error.SkipZigTest; // TODO
6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO12 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -116,7 +120,7 @@ fn vector32() !void {...@@ -116,7 +120,7 @@ fn vector32() !void {
116120
117test "vector f32" {121test "vector f32" {
118 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO122 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
119 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO123 if (no_x86_64_hardware_fma_support) return error.SkipZigTest; // TODO
120 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO124 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
121 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO125 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
122 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO126 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -139,7 +143,7 @@ fn vector64() !void {...@@ -139,7 +143,7 @@ fn vector64() !void {
139143
140test "vector f64" {144test "vector f64" {
141 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO145 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
142 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO146 if (no_x86_64_hardware_fma_support) return error.SkipZigTest; // TODO
143 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO147 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
145 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO149 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/vector.zig+2-1
...@@ -168,7 +168,8 @@ test "array to vector" {...@@ -168,7 +168,8 @@ test "array to vector" {
168168
169test "array to vector with element type coercion" {169test "array to vector with element type coercion" {
170 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO170 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
171 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO171 if (builtin.zig_backend == .stage2_x86_64 and
172 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .f16c)) return error.SkipZigTest; // TODO
172 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO173 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
173 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO174 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
174 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO175 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO