authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-06 06:00:22-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-08 07:36:19-04:00
log5d4288c5f6c69bdd4cbd9b3580016828e38f087d
treec5d1804ee4759fdf4cdd8cb8f649ad3f2fe16c00
parentae588a09f2c2146ada0f914c7d279f69a0d79396

x86_64: fix unordered float equality


8 files changed, 599 insertions(+), 363 deletions(-)

src/arch/x86_64/CodeGen.zig+261-154
...@@ -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 } };
...@@ -1016,7 +1007,14 @@ fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void {...@@ -1016,7 +1007,14 @@ fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void {
1016 _ = try self.addInst(.{1007 _ = try self.addInst(.{
1017 .tag = .setcc,1008 .tag = .setcc,
1018 .ops = .r_cc,1009 .ops = .r_cc,
1019 .data = .{ .r_cc = .{ .r = reg, .cc = cc } },1010 .data = .{ .r_cc = .{
1011 .r = reg,
1012 .scratch = if (cc == .z_and_np or cc == .nz_or_p)
1013 (try self.register_manager.allocReg(null, gp)).to8()
1014 else
1015 .none,
1016 .cc = cc,
1017 } },
1020 });1018 });
1021}1019}
10221020
...@@ -1028,23 +1026,36 @@ fn asmSetccMemory(self: *Self, m: Memory, cc: bits.Condition) !void {...@@ -1028,23 +1026,36 @@ fn asmSetccMemory(self: *Self, m: Memory, cc: bits.Condition) !void {
1028 .rip => .m_rip_cc,1026 .rip => .m_rip_cc,
1029 else => unreachable,1027 else => unreachable,
1030 },1028 },
1031 .data = .{ .x_cc = .{ .cc = cc, .payload = switch (m) {1029 .data = .{ .x_cc = .{
1032 .sib => try self.addExtra(Mir.MemorySib.encode(m)),1030 .scratch = if (cc == .z_and_np or cc == .nz_or_p)
1033 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),1031 (try self.register_manager.allocReg(null, gp)).to8()
1034 else => unreachable,1032 else
1035 } } },1033 .none,
1034 .cc = cc,
1035 .payload = switch (m) {
1036 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1037 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1038 else => unreachable,
1039 },
1040 } },
1036 });1041 });
1037}1042}
10381043
1044/// A `cc` of `.z_and_np` clobbers `reg2`!
1039fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bits.Condition) !void {1045fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bits.Condition) !void {
1040 _ = try self.addInst(.{1046 _ = try self.addInst(.{
1041 .tag = .cmovcc,1047 .tag = .cmovcc,
1042 .ops = .rr_cc,1048 .ops = .rr_cc,
1043 .data = .{ .rr_cc = .{ .r1 = reg1, .r2 = reg2, .cc = cc } },1049 .data = .{ .rr_cc = .{
1050 .r1 = reg1,
1051 .r2 = reg2,
1052 .cc = cc,
1053 } },
1044 });1054 });
1045}1055}
10461056
1047fn asmCmovccRegisterMemory(self: *Self, reg: Register, m: Memory, cc: bits.Condition) !void {1057fn asmCmovccRegisterMemory(self: *Self, reg: Register, m: Memory, cc: bits.Condition) !void {
1058 assert(cc != .z_and_np); // not supported
1048 _ = try self.addInst(.{1059 _ = try self.addInst(.{
1049 .tag = .cmovcc,1060 .tag = .cmovcc,
1050 .ops = switch (m) {1061 .ops = switch (m) {
...@@ -1052,11 +1063,15 @@ fn asmCmovccRegisterMemory(self: *Self, reg: Register, m: Memory, cc: bits.Condi...@@ -1052,11 +1063,15 @@ fn asmCmovccRegisterMemory(self: *Self, reg: Register, m: Memory, cc: bits.Condi
1052 .rip => .rm_rip_cc,1063 .rip => .rm_rip_cc,
1053 else => unreachable,1064 else => unreachable,
1054 },1065 },
1055 .data = .{ .rx_cc = .{ .r = reg, .cc = cc, .payload = switch (m) {1066 .data = .{ .rx_cc = .{
1056 .sib => try self.addExtra(Mir.MemorySib.encode(m)),1067 .r = reg,
1057 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),1068 .cc = cc,
1058 else => unreachable,1069 .payload = switch (m) {
1059 } } },1070 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1071 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1072 else => unreachable,
1073 },
1074 } },
1060 });1075 });
1061}1076}
10621077
...@@ -1131,10 +1146,13 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Imme...@@ -1131,10 +1146,13 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Imme
1131 .tag = tag,1146 .tag = tag,
1132 .ops = ops,1147 .ops = ops,
1133 .data = switch (ops) {1148 .data = switch (ops) {
1134 .ri_s, .ri_u => .{ .ri = .{ .r = reg, .i = switch (imm) {1149 .ri_s, .ri_u => .{ .ri = .{
1135 .signed => |s| @bitCast(u32, s),1150 .r = reg,
1136 .unsigned => |u| @intCast(u32, u),1151 .i = switch (imm) {
1137 } } },1152 .signed => |s| @bitCast(u32, s),
1153 .unsigned => |u| @intCast(u32, u),
1154 },
1155 } },
1138 .ri64 => .{ .rx = .{1156 .ri64 => .{ .rx = .{
1139 .r = reg,1157 .r = reg,
1140 .payload = try self.addExtra(Mir.Imm64.encode(imm.unsigned)),1158 .payload = try self.addExtra(Mir.Imm64.encode(imm.unsigned)),
...@@ -1171,10 +1189,14 @@ fn asmRegisterRegisterImmediate(...@@ -1171,10 +1189,14 @@ fn asmRegisterRegisterImmediate(
1171 .signed => .rri_s,1189 .signed => .rri_s,
1172 .unsigned => .rri_u,1190 .unsigned => .rri_u,
1173 },1191 },
1174 .data = .{ .rri = .{ .r1 = reg1, .r2 = reg2, .i = switch (imm) {1192 .data = .{ .rri = .{
1175 .signed => |s| @bitCast(u32, s),1193 .r1 = reg1,
1176 .unsigned => |u| @intCast(u32, u),1194 .r2 = reg2,
1177 } } },1195 .i = switch (imm) {
1196 .signed => |s| @bitCast(u32, s),
1197 .unsigned => |u| @intCast(u32, u),
1198 },
1199 } },
1178 });1200 });
1179}1201}
11801202
...@@ -1202,11 +1224,14 @@ fn asmRegisterMemory(self: *Self, tag: Mir.Inst.Tag, reg: Register, m: Memory) !...@@ -1202,11 +1224,14 @@ fn asmRegisterMemory(self: *Self, tag: Mir.Inst.Tag, reg: Register, m: Memory) !
1202 .rip => .rm_rip,1224 .rip => .rm_rip,
1203 else => unreachable,1225 else => unreachable,
1204 },1226 },
1205 .data = .{ .rx = .{ .r = reg, .payload = switch (m) {1227 .data = .{ .rx = .{
1206 .sib => try self.addExtra(Mir.MemorySib.encode(m)),1228 .r = reg,
1207 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),1229 .payload = switch (m) {
1208 else => unreachable,1230 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1209 } } },1231 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1232 else => unreachable,
1233 },
1234 } },
1210 });1235 });
1211}1236}
12121237
...@@ -1224,11 +1249,43 @@ fn asmRegisterMemoryImmediate(...@@ -1224,11 +1249,43 @@ fn asmRegisterMemoryImmediate(
1224 .rip => .rmi_rip,1249 .rip => .rmi_rip,
1225 else => unreachable,1250 else => unreachable,
1226 },1251 },
1227 .data = .{ .rix = .{ .r = reg, .i = @intCast(u8, imm.unsigned), .payload = switch (m) {1252 .data = .{ .rix = .{
1228 .sib => try self.addExtra(Mir.MemorySib.encode(m)),1253 .r = reg,
1229 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),1254 .i = @intCast(u8, imm.unsigned),
1255 .payload = switch (m) {
1256 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1257 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1258 else => unreachable,
1259 },
1260 } },
1261 });
1262}
1263
1264fn asmRegisterRegisterMemoryImmediate(
1265 self: *Self,
1266 tag: Mir.Inst.Tag,
1267 reg1: Register,
1268 reg2: Register,
1269 m: Memory,
1270 imm: Immediate,
1271) !void {
1272 _ = try self.addInst(.{
1273 .tag = tag,
1274 .ops = switch (m) {
1275 .sib => .rrmi_sib,
1276 .rip => .rrmi_rip,
1230 else => unreachable,1277 else => unreachable,
1231 } } },1278 },
1279 .data = .{ .rrix = .{
1280 .r1 = reg1,
1281 .r2 = reg2,
1282 .i = @intCast(u8, imm.unsigned),
1283 .payload = switch (m) {
1284 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1285 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1286 else => unreachable,
1287 },
1288 } },
1232 });1289 });
1233}1290}
12341291
...@@ -1240,11 +1297,14 @@ fn asmMemoryRegister(self: *Self, tag: Mir.Inst.Tag, m: Memory, reg: Register) !...@@ -1240,11 +1297,14 @@ fn asmMemoryRegister(self: *Self, tag: Mir.Inst.Tag, m: Memory, reg: Register) !
1240 .rip => .mr_rip,1297 .rip => .mr_rip,
1241 else => unreachable,1298 else => unreachable,
1242 },1299 },
1243 .data = .{ .rx = .{ .r = reg, .payload = switch (m) {1300 .data = .{ .rx = .{
1244 .sib => try self.addExtra(Mir.MemorySib.encode(m)),1301 .r = reg,
1245 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),1302 .payload = switch (m) {
1246 else => unreachable,1303 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1247 } } },1304 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1305 else => unreachable,
1306 },
1307 } },
1248 });1308 });
1249}1309}
12501310
...@@ -1262,14 +1322,17 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.Tag, m: Memory, imm: Immediate)...@@ -1262,14 +1322,17 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.Tag, m: Memory, imm: Immediate)
1262 },1322 },
1263 else => unreachable,1323 else => unreachable,
1264 },1324 },
1265 .data = .{ .ix = .{ .i = switch (imm) {1325 .data = .{ .ix = .{
1266 .signed => |s| @bitCast(u32, s),1326 .i = switch (imm) {
1267 .unsigned => |u| @intCast(u32, u),1327 .signed => |s| @bitCast(u32, s),
1268 }, .payload = switch (m) {1328 .unsigned => |u| @intCast(u32, u),
1269 .sib => try self.addExtra(Mir.MemorySib.encode(m)),1329 },
1270 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),1330 .payload = switch (m) {
1271 else => unreachable,1331 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1272 } } },1332 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1333 else => unreachable,
1334 },
1335 } },
1273 });1336 });
1274}1337}
12751338
...@@ -6612,11 +6675,13 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -6612,11 +6675,13 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
6612 _ = try self.addInst(.{6675 _ = try self.addInst(.{
6613 .tag = .mov_linker,6676 .tag = .mov_linker,
6614 .ops = .import_reloc,6677 .ops = .import_reloc,
6615 .data = .{ .payload = try self.addExtra(Mir.LeaRegisterReloc{6678 .data = .{ .rx = .{
6616 .reg = @enumToInt(Register.rax),6679 .r = .rax,
6617 .atom_index = atom_index,6680 .payload = try self.addExtra(Mir.Reloc{
6618 .sym_index = sym_index,6681 .atom_index = atom_index,
6619 }) },6682 .sym_index = sym_index,
6683 }),
6684 } },
6620 });6685 });
6621 try self.asmRegister(.call, .rax);6686 try self.asmRegister(.call, .rax);
6622 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {6687 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
...@@ -6695,8 +6760,6 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -6695,8 +6760,6 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
6695fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {6760fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
6696 const bin_op = self.air.instructions.items(.data)[inst].bin_op;6761 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
6697 const ty = self.air.typeOf(bin_op.lhs);6762 const ty = self.air.typeOf(bin_op.lhs);
6698 const ty_abi_size = ty.abiSize(self.target.*);
6699 const can_reuse = ty_abi_size <= 8;
67006763
6701 try self.spillEflagsIfOccupied();6764 try self.spillEflagsIfOccupied();
6702 self.eflags_inst = inst;6765 self.eflags_inst = inst;
...@@ -6715,69 +6778,93 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -6715,69 +6778,93 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
6715 };6778 };
6716 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);6779 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
67176780
6718 const dst_mem_ok = !ty.isRuntimeFloat();6781 const result = MCValue{
6719 var flipped = false;6782 .eflags = switch (ty.zigTypeTag()) {
6720 const dst_mcv: MCValue = if (can_reuse and !lhs_mcv.isImmediate() and6783 else => result: {
6721 (dst_mem_ok or lhs_mcv.isRegister()) and self.liveness.operandDies(inst, 0))6784 var flipped = false;
6722 lhs_mcv6785 const dst_mcv: MCValue = if (lhs_mcv.isRegister() or lhs_mcv.isMemory())
6723 else if (can_reuse and !rhs_mcv.isImmediate() and6786 lhs_mcv
6724 (dst_mem_ok or rhs_mcv.isRegister()) and self.liveness.operandDies(inst, 1))6787 else if (rhs_mcv.isRegister() or rhs_mcv.isMemory()) dst: {
6725 dst: {6788 flipped = true;
6726 flipped = true;6789 break :dst rhs_mcv;
6727 break :dst rhs_mcv;6790 } else .{ .register = try self.copyToTmpRegister(ty, lhs_mcv) };
6728 } else if (dst_mem_ok) dst: {6791 const dst_lock = switch (dst_mcv) {
6729 const dst_mcv = try self.allocTempRegOrMem(ty, true);6792 .register => |reg| self.register_manager.lockReg(reg),
6730 try self.genCopy(ty, dst_mcv, lhs_mcv);6793 else => null,
6731 break :dst dst_mcv;6794 };
6732 } else .{ .register = try self.copyToTmpRegister(ty, lhs_mcv) };6795 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
6733 const dst_lock = switch (dst_mcv) {6796 const src_mcv = if (flipped) lhs_mcv else rhs_mcv;
6734 .register => |reg| self.register_manager.lockReg(reg),
6735 else => null,
6736 };
6737 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
6738
6739 const src_mcv = if (flipped) lhs_mcv else rhs_mcv;
6740 switch (ty.zigTypeTag()) {
6741 else => try self.genBinOpMir(.cmp, ty, dst_mcv, src_mcv),
6742 .Float => switch (ty.floatBits(self.target.*)) {
6743 16 => if (self.hasFeature(.f16c)) {
6744 const dst_reg = dst_mcv.getReg().?.to128();
67456797
6746 const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();6798 try self.genBinOpMir(.cmp, ty, dst_mcv, src_mcv);
6747 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);6799 break :result Condition.fromCompareOperator(
6748 defer self.register_manager.unlockReg(tmp_lock);6800 if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned,
6801 if (flipped) op.reverse() else op,
6802 );
6803 },
6804 .Float => result: {
6805 const flipped = switch (op) {
6806 .lt, .lte => true,
6807 .eq, .gte, .gt, .neq => false,
6808 };
67496809
6750 if (src_mcv.isRegister())6810 const dst_mcv = if (flipped) rhs_mcv else lhs_mcv;
6751 try self.asmRegisterRegisterRegister(6811 const dst_reg = if (dst_mcv.isRegister())
6752 .vpunpcklwd,6812 dst_mcv.getReg().?
6753 dst_reg,
6754 dst_reg,
6755 src_mcv.getReg().?.to128(),
6756 )
6757 else6813 else
6758 try self.asmRegisterMemoryImmediate(6814 try self.copyToTmpRegister(ty, dst_mcv);
6759 .vpinsrw,6815 const dst_lock = self.register_manager.lockReg(dst_reg);
6760 dst_reg,6816 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
6761 src_mcv.mem(.word),6817 const src_mcv = if (flipped) lhs_mcv else rhs_mcv;
6762 Immediate.u(1),6818
6763 );6819 switch (ty.floatBits(self.target.*)) {
6764 try self.asmRegisterRegister(.vcvtph2ps, dst_reg, dst_reg);6820 16 => if (self.hasFeature(.f16c)) {
6765 try self.asmRegisterRegister(.vmovshdup, tmp_reg, dst_reg);6821 const tmp1_reg = (try self.register_manager.allocReg(null, sse)).to128();
6766 try self.genBinOpMir(.ucomiss, ty, dst_mcv, .{ .register = tmp_reg });6822 const tmp1_mcv = MCValue{ .register = tmp1_reg };
6767 } else return self.fail("TODO implement airCmp for {}", .{6823 const tmp1_lock = self.register_manager.lockRegAssumeUnused(tmp1_reg);
6768 ty.fmt(self.bin_file.options.module.?),6824 defer self.register_manager.unlockReg(tmp1_lock);
6769 }),6825
6770 32 => try self.genBinOpMir(.ucomiss, ty, dst_mcv, src_mcv),6826 const tmp2_reg = (try self.register_manager.allocReg(null, sse)).to128();
6771 64 => try self.genBinOpMir(.ucomisd, ty, dst_mcv, src_mcv),6827 const tmp2_mcv = MCValue{ .register = tmp2_reg };
6772 else => return self.fail("TODO implement airCmp for {}", .{6828 const tmp2_lock = self.register_manager.lockRegAssumeUnused(tmp2_reg);
6773 ty.fmt(self.bin_file.options.module.?),6829 defer self.register_manager.unlockReg(tmp2_lock);
6774 }),6830
6775 },6831 if (src_mcv.isRegister())
6776 }6832 try self.asmRegisterRegisterRegister(
6833 .vpunpcklwd,
6834 tmp1_reg,
6835 dst_reg.to128(),
6836 src_mcv.getReg().?.to128(),
6837 )
6838 else
6839 try self.asmRegisterRegisterMemoryImmediate(
6840 .vpinsrw,
6841 tmp1_reg,
6842 dst_reg.to128(),
6843 src_mcv.mem(.word),
6844 Immediate.u(1),
6845 );
6846 try self.asmRegisterRegister(.vcvtph2ps, tmp1_reg, tmp1_reg);
6847 try self.asmRegisterRegister(.vmovshdup, tmp2_reg, tmp1_reg);
6848 try self.genBinOpMir(.ucomiss, ty, tmp1_mcv, tmp2_mcv);
6849 } else return self.fail("TODO implement airCmp for {}", .{
6850 ty.fmt(self.bin_file.options.module.?),
6851 }),
6852 32 => try self.genBinOpMir(.ucomiss, ty, .{ .register = dst_reg }, src_mcv),
6853 64 => try self.genBinOpMir(.ucomisd, ty, .{ .register = dst_reg }, src_mcv),
6854 else => return self.fail("TODO implement airCmp for {}", .{
6855 ty.fmt(self.bin_file.options.module.?),
6856 }),
6857 }
67776858
6778 const signedness = if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned;6859 break :result switch (if (flipped) op.reverse() else op) {
6779 const result = MCValue{6860 .lt, .lte => unreachable, // required to have been canonicalized to gt(e)
6780 .eflags = Condition.fromCompareOperator(signedness, if (flipped) op.reverse() else op),6861 .gt => .a,
6862 .gte => .ae,
6863 .eq => .z_and_np,
6864 .neq => .nz_or_p,
6865 };
6866 },
6867 },
6781 };6868 };
6782 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });6869 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
6783}6870}
...@@ -7929,11 +8016,13 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -7929,11 +8016,13 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
7929 _ = try self.addInst(.{8016 _ = try self.addInst(.{
7930 .tag = .mov_linker,8017 .tag = .mov_linker,
7931 .ops = .direct_reloc,8018 .ops = .direct_reloc,
7932 .data = .{ .payload = try self.addExtra(Mir.LeaRegisterReloc{8019 .data = .{ .rx = .{
7933 .reg = @enumToInt(dst_reg.to64()),8020 .r = dst_reg.to64(),
7934 .atom_index = atom_index,8021 .payload = try self.addExtra(Mir.Reloc{
7935 .sym_index = sym_index,8022 .atom_index = atom_index,
7936 }) },8023 .sym_index = sym_index,
8024 }),
8025 } },
7937 });8026 });
7938 return;8027 return;
7939 },8028 },
...@@ -7975,11 +8064,13 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -7975,11 +8064,13 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
7975 .lea_got => .got_reloc,8064 .lea_got => .got_reloc,
7976 else => unreachable,8065 else => unreachable,
7977 },8066 },
7978 .data = .{ .payload = try self.addExtra(Mir.LeaRegisterReloc{8067 .data = .{ .rx = .{
7979 .reg = @enumToInt(dst_reg.to64()),8068 .r = dst_reg.to64(),
7980 .atom_index = atom_index,8069 .payload = try self.addExtra(Mir.Reloc{
7981 .sym_index = sym_index,8070 .atom_index = atom_index,
7982 }) },8071 .sym_index = sym_index,
8072 }),
8073 } },
7983 });8074 });
7984 },8075 },
7985 .lea_tlv => |sym_index| {8076 .lea_tlv => |sym_index| {
...@@ -7988,11 +8079,13 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -7988,11 +8079,13 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
7988 _ = try self.addInst(.{8079 _ = try self.addInst(.{
7989 .tag = .lea_linker,8080 .tag = .lea_linker,
7990 .ops = .tlv_reloc,8081 .ops = .tlv_reloc,
7991 .data = .{ .payload = try self.addExtra(Mir.LeaRegisterReloc{8082 .data = .{ .rx = .{
7992 .reg = @enumToInt(Register.rdi),8083 .r = .rdi,
7993 .atom_index = atom_index,8084 .payload = try self.addExtra(Mir.Reloc{
7994 .sym_index = sym_index,8085 .atom_index = atom_index,
7995 }) },8086 .sym_index = sym_index,
8087 }),
8088 } },
7996 });8089 });
7997 // TODO: spill registers before calling8090 // TODO: spill registers before calling
7998 try self.asmMemory(.call, Memory.sib(.qword, .{ .base = .{ .reg = .rdi } }));8091 try self.asmMemory(.call, Memory.sib(.qword, .{ .base = .{ .reg = .rdi } }));
...@@ -8463,14 +8556,20 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {...@@ -8463,14 +8556,20 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
84638556
8464 try self.spillEflagsIfOccupied();8557 try self.spillEflagsIfOccupied();
8465 if (val_abi_size <= 8) {8558 if (val_abi_size <= 8) {
8466 _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{8559 _ = try self.addInst(.{
8467 .r = registerAlias(new_reg.?, val_abi_size),8560 .tag = .cmpxchg,
8468 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),8561 .ops = .lock_mr_sib,
8469 } } });8562 .data = .{ .rx = .{
8563 .r = registerAlias(new_reg.?, val_abi_size),
8564 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
8565 } },
8566 });
8470 } else {8567 } else {
8471 _ = try self.addInst(.{ .tag = .cmpxchgb, .ops = .lock_m_sib, .data = .{8568 _ = try self.addInst(.{
8472 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),8569 .tag = .cmpxchgb,
8473 } });8570 .ops = .lock_m_sib,
8571 .data = .{ .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)) },
8572 });
8474 }8573 }
84758574
8476 const result: MCValue = result: {8575 const result: MCValue = result: {
...@@ -8571,14 +8670,18 @@ fn atomicOp(...@@ -8571,14 +8670,18 @@ fn atomicOp(
8571 if (rmw_op == std.builtin.AtomicRmwOp.Sub and tag == .xadd) {8670 if (rmw_op == std.builtin.AtomicRmwOp.Sub and tag == .xadd) {
8572 try self.genUnOpMir(.neg, val_ty, dst_mcv);8671 try self.genUnOpMir(.neg, val_ty, dst_mcv);
8573 }8672 }
8574 _ = try self.addInst(.{ .tag = tag, .ops = switch (tag) {8673 _ = try self.addInst(.{
8575 .mov, .xchg => .mr_sib,8674 .tag = tag,
8576 .xadd, .add, .sub, .@"and", .@"or", .xor => .lock_mr_sib,8675 .ops = switch (tag) {
8577 else => unreachable,8676 .mov, .xchg => .mr_sib,
8578 }, .data = .{ .rx = .{8677 .xadd, .add, .sub, .@"and", .@"or", .xor => .lock_mr_sib,
8579 .r = registerAlias(dst_reg, val_abi_size),8678 else => unreachable,
8580 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),8679 },
8581 } } });8680 .data = .{ .rx = .{
8681 .r = registerAlias(dst_reg, val_abi_size),
8682 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
8683 } },
8684 });
85828685
8583 return if (unused) .unreach else dst_mcv;8686 return if (unused) .unreach else dst_mcv;
8584 },8687 },
...@@ -8645,10 +8748,14 @@ fn atomicOp(...@@ -8645,10 +8748,14 @@ fn atomicOp(
8645 }8748 }
8646 },8749 },
8647 };8750 };
8648 _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{8751 _ = try self.addInst(.{
8649 .r = registerAlias(tmp_reg, val_abi_size),8752 .tag = .cmpxchg,
8650 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),8753 .ops = .lock_mr_sib,
8651 } } });8754 .data = .{ .rx = .{
8755 .r = registerAlias(tmp_reg, val_abi_size),
8756 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
8757 } },
8758 });
8652 _ = try self.asmJccReloc(loop, .ne);8759 _ = try self.asmJccReloc(loop, .ne);
8653 return if (unused) .unreach else .{ .register = .rax };8760 return if (unused) .unreach else .{ .register = .rax };
8654 } else {8761 } else {
src/arch/x86_64/Emit.zig+140-133
...@@ -18,142 +18,149 @@ pub const Error = Lower.Error || error{...@@ -18,142 +18,149 @@ 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 .@"extern" => |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 });
129121 } else return emit.fail("TODO implement linker reloc for {s}", .{
130 .dbg_prologue_end => {122 @tagName(emit.bin_file.tag),
131 switch (emit.debug_output) {123 }),
132 .dwarf => |dw| {124 };
133 try dw.setPrologueEnd();125 }
134 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{126 std.debug.assert(lowered_relocs.len == 0);
135 emit.prev_di_line, emit.prev_di_column,
136 });
137 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
138 },
139 .plan9 => {},
140 .none => {},
141 }
142 },
143127
144 .dbg_epilogue_begin => {128 if (lowered.insts.len == 0) {
145 switch (emit.debug_output) {129 const mir_inst = emit.lower.mir.instructions.get(mir_index);
146 .dwarf => |dw| {130 switch (mir_inst.tag) {
147 try dw.setEpilogueBegin();131 else => unreachable,
148 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{132 .dead => {},
149 emit.prev_di_line, emit.prev_di_column,133 .dbg_line => try emit.dbgAdvancePCAndLine(
150 });134 mir_inst.data.line_column.line,
151 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);135 mir_inst.data.line_column.column,
152 },136 ),
153 .plan9 => {},137 .dbg_prologue_end => {
154 .none => {},138 switch (emit.debug_output) {
155 }139 .dwarf => |dw| {
156 },140 try dw.setPrologueEnd();
141 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{
142 emit.prev_di_line, emit.prev_di_column,
143 });
144 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
145 },
146 .plan9 => {},
147 .none => {},
148 }
149 },
150 .dbg_epilogue_begin => {
151 switch (emit.debug_output) {
152 .dwarf => |dw| {
153 try dw.setEpilogueBegin();
154 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{
155 emit.prev_di_line, emit.prev_di_column,
156 });
157 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
158 },
159 .plan9 => {},
160 .none => {},
161 }
162 },
163 }
157 }164 }
158 }165 }
159 try emit.fixupRelocs();166 try emit.fixupRelocs();
src/arch/x86_64/Lower.zig+166-54
...@@ -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,13 +29,35 @@ pub const Error = error{...@@ -20,13 +29,35 @@ 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 @"extern": 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 .adc,
32 .add,63 .add,
...@@ -185,22 +216,26 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {...@@ -185,22 +216,26 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {
185216
186 .cmpxchgb => try lower.mirCmpxchgBytes(inst),217 .cmpxchgb => try lower.mirCmpxchgBytes(inst),
187218
188 .jmp_reloc => try lower.emit(.none, .jmp, &.{.{ .imm = Immediate.s(0) }}),219 .jmp_reloc => try lower.emitInstWithReloc(.none, .jmp, &.{
220 .{ .imm = Immediate.s(0) },
221 }, .{ .inst = inst.data.inst }),
189222
190 .call_extern => try lower.emit(.none, .call, &.{.{ .imm = Immediate.s(0) }}),223 .call_extern => try lower.emitInstWithReloc(.none, .call, &.{
224 .{ .imm = Immediate.s(0) },
225 }, .{ .@"extern" = inst.data.relocation }),
191226
192 .lea_linker => try lower.mirLeaLinker(inst),227 .lea_linker => try lower.mirLinker(.lea, inst),
193 .mov_linker => try lower.mirMovLinker(inst),228 .mov_linker => try lower.mirLinker(.mov, inst),
194229
195 .mov_moffs => try lower.mirMovMoffs(inst),230 .mov_moffs => try lower.mirMovMoffs(inst),
196231
197 .movsx => try lower.mirMovsx(inst),232 .movsx => try lower.mirMovsx(inst),
198 .cmovcc => try lower.mirCmovcc(inst),233 .cmovcc => try lower.mirCmovcc(inst),
199 .setcc => try lower.mirSetcc(inst),234 .setcc => try lower.mirSetcc(inst),
200 .jcc => try lower.emit(.none, mnem_cc(.j, inst.data.inst_cc.cc), &.{.{ .imm = Immediate.s(0) }}),235 .jcc => try lower.mirJcc(index, inst),
201236
202 .push_regs => try lower.mirPushPopRegisterList(inst, .push),237 .push_regs => try lower.mirRegisterList(.push, inst),
203 .pop_regs => try lower.mirPushPopRegisterList(inst, .pop),238 .pop_regs => try lower.mirRegisterList(.pop, inst),
204239
205 .dbg_line,240 .dbg_line,
206 .dbg_prologue_end,241 .dbg_prologue_end,
...@@ -209,7 +244,10 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {...@@ -209,7 +244,10 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {
209 => {},244 => {},
210 }245 }
211246
212 return lower.result[0..lower.result_len];247 return .{
248 .insts = lower.result_insts[0..lower.result_insts_len],
249 .relocs = lower.result_relocs[0..lower.result_relocs_len],
250 };
213}251}
214252
215pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error {253pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error {
...@@ -221,7 +259,10 @@ pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error {...@@ -221,7 +259,10 @@ pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error {
221259
222fn mnem_cc(comptime base: @Type(.EnumLiteral), cc: bits.Condition) Mnemonic {260fn mnem_cc(comptime base: @Type(.EnumLiteral), cc: bits.Condition) Mnemonic {
223 return switch (cc) {261 return switch (cc) {
224 inline else => |c| @field(Mnemonic, @tagName(base) ++ @tagName(c)),262 inline else => |c| if (@hasField(Mnemonic, @tagName(base) ++ @tagName(c)))
263 @field(Mnemonic, @tagName(base) ++ @tagName(c))
264 else
265 unreachable,
225 };266 };
226}267}
227268
...@@ -247,6 +288,8 @@ fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {...@@ -247,6 +288,8 @@ fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
247 .rmi_rip,288 .rmi_rip,
248 .mri_sib,289 .mri_sib,
249 .mri_rip,290 .mri_rip,
291 .rrmi_sib,
292 .rrmi_rip,
250 => Immediate.u(i),293 => Immediate.u(i),
251294
252 .ri64 => Immediate.u(lower.mir.extraData(Mir.Imm64, i).data.decode()),295 .ri64 => Immediate.u(lower.mir.extraData(Mir.Imm64, i).data.decode()),
...@@ -267,6 +310,7 @@ fn mem(lower: Lower, ops: Mir.Inst.Ops, payload: u32) Memory {...@@ -267,6 +310,7 @@ fn mem(lower: Lower, ops: Mir.Inst.Ops, payload: u32) Memory {
267 .mr_sib,310 .mr_sib,
268 .mrr_sib,311 .mrr_sib,
269 .mri_sib,312 .mri_sib,
313 .rrmi_sib,
270 .lock_m_sib,314 .lock_m_sib,
271 .lock_mi_sib_u,315 .lock_mi_sib_u,
272 .lock_mi_sib_s,316 .lock_mi_sib_s,
...@@ -283,6 +327,7 @@ fn mem(lower: Lower, ops: Mir.Inst.Ops, payload: u32) Memory {...@@ -283,6 +327,7 @@ fn mem(lower: Lower, ops: Mir.Inst.Ops, payload: u32) Memory {
283 .mr_rip,327 .mr_rip,
284 .mrr_rip,328 .mrr_rip,
285 .mri_rip,329 .mri_rip,
330 .rrmi_rip,
286 .lock_m_rip,331 .lock_m_rip,
287 .lock_mi_rip_u,332 .lock_mi_rip_u,
288 .lock_mi_rip_s,333 .lock_mi_rip_s,
...@@ -298,13 +343,28 @@ fn mem(lower: Lower, ops: Mir.Inst.Ops, payload: u32) Memory {...@@ -298,13 +343,28 @@ fn mem(lower: Lower, ops: Mir.Inst.Ops, payload: u32) Memory {
298 });343 });
299}344}
300345
301fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void {346fn emitInst(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void {
302 lower.result[lower.result_len] = try Instruction.new(prefix, mnemonic, ops);347 lower.result_insts[lower.result_insts_len] = try Instruction.new(prefix, mnemonic, ops);
303 lower.result_len += 1;348 lower.result_insts_len += 1;
349}
350
351fn emitInstWithReloc(
352 lower: *Lower,
353 prefix: Prefix,
354 mnemonic: Mnemonic,
355 ops: []const Operand,
356 target: Reloc.Target,
357) Error!void {
358 lower.result_relocs[lower.result_relocs_len] = .{
359 .lowered_inst_index = lower.result_insts_len,
360 .target = target,
361 };
362 lower.result_relocs_len += 1;
363 try lower.emitInst(prefix, mnemonic, ops);
304}364}
305365
306fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {366fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {
307 try lower.emit(switch (inst.ops) {367 try lower.emitInst(switch (inst.ops) {
308 else => .none,368 else => .none,
309 .lock_m_sib,369 .lock_m_sib,
310 .lock_m_rip,370 .lock_m_rip,
...@@ -389,13 +449,19 @@ fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {...@@ -389,13 +449,19 @@ fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {
389 .{ .reg = inst.data.rix.r },449 .{ .reg = inst.data.rix.r },
390 .{ .imm = lower.imm(inst.ops, inst.data.rix.i) },450 .{ .imm = lower.imm(inst.ops, inst.data.rix.i) },
391 },451 },
452 .rrmi_sib, .rrmi_rip => &.{
453 .{ .reg = inst.data.rrix.r1 },
454 .{ .reg = inst.data.rrix.r2 },
455 .{ .mem = lower.mem(inst.ops, inst.data.rrix.payload) },
456 .{ .imm = lower.imm(inst.ops, inst.data.rrix.i) },
457 },
392 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),458 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
393 });459 });
394}460}
395461
396fn mirString(lower: *Lower, inst: Mir.Inst) Error!void {462fn mirString(lower: *Lower, inst: Mir.Inst) Error!void {
397 switch (inst.ops) {463 switch (inst.ops) {
398 .string => try lower.emit(switch (inst.data.string.repeat) {464 .string => try lower.emitInst(switch (inst.data.string.repeat) {
399 inline else => |repeat| @field(Prefix, @tagName(repeat)),465 inline else => |repeat| @field(Prefix, @tagName(repeat)),
400 }, switch (inst.tag) {466 }, switch (inst.tag) {
401 inline .cmps, .lods, .movs, .scas, .stos => |tag| switch (inst.data.string.width) {467 inline .cmps, .lods, .movs, .scas, .stos => |tag| switch (inst.data.string.width) {
...@@ -414,7 +480,7 @@ fn mirCmpxchgBytes(lower: *Lower, inst: Mir.Inst) Error!void {...@@ -414,7 +480,7 @@ fn mirCmpxchgBytes(lower: *Lower, inst: Mir.Inst) Error!void {
414 },480 },
415 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),481 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
416 };482 };
417 try lower.emit(switch (inst.ops) {483 try lower.emitInst(switch (inst.ops) {
418 .m_sib, .m_rip => .none,484 .m_sib, .m_rip => .none,
419 .lock_m_sib, .lock_m_rip => .lock,485 .lock_m_sib, .lock_m_rip => .lock,
420 else => unreachable,486 else => unreachable,
...@@ -426,7 +492,7 @@ fn mirCmpxchgBytes(lower: *Lower, inst: Mir.Inst) Error!void {...@@ -426,7 +492,7 @@ fn mirCmpxchgBytes(lower: *Lower, inst: Mir.Inst) Error!void {
426}492}
427493
428fn mirMovMoffs(lower: *Lower, inst: Mir.Inst) Error!void {494fn mirMovMoffs(lower: *Lower, inst: Mir.Inst) Error!void {
429 try lower.emit(switch (inst.ops) {495 try lower.emitInst(switch (inst.ops) {
430 .rax_moffs, .moffs_rax => .none,496 .rax_moffs, .moffs_rax => .none,
431 .lock_moffs_rax => .lock,497 .lock_moffs_rax => .lock,
432 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),498 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
...@@ -455,7 +521,7 @@ fn mirMovsx(lower: *Lower, inst: Mir.Inst) Error!void {...@@ -455,7 +521,7 @@ fn mirMovsx(lower: *Lower, inst: Mir.Inst) Error!void {
455 },521 },
456 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),522 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
457 };523 };
458 try lower.emit(.none, switch (ops[0].bitSize()) {524 try lower.emitInst(.none, switch (ops[0].bitSize()) {
459 32, 64 => switch (ops[1].bitSize()) {525 32, 64 => switch (ops[1].bitSize()) {
460 32 => .movsxd,526 32 => .movsxd,
461 else => .movsx,527 else => .movsx,
...@@ -465,32 +531,82 @@ fn mirMovsx(lower: *Lower, inst: Mir.Inst) Error!void {...@@ -465,32 +531,82 @@ fn mirMovsx(lower: *Lower, inst: Mir.Inst) Error!void {
465}531}
466532
467fn mirCmovcc(lower: *Lower, inst: Mir.Inst) Error!void {533fn mirCmovcc(lower: *Lower, inst: Mir.Inst) Error!void {
468 switch (inst.ops) {534 const data: struct { cc: bits.Condition, ops: [2]Operand } = switch (inst.ops) {
469 .rr_cc => try lower.emit(.none, mnem_cc(.cmov, inst.data.rr_cc.cc), &.{535 .rr_cc => .{ .cc = inst.data.rr_cc.cc, .ops = .{
470 .{ .reg = inst.data.rr_cc.r1 },536 .{ .reg = inst.data.rr_cc.r1 },
471 .{ .reg = inst.data.rr_cc.r2 },537 .{ .reg = inst.data.rr_cc.r2 },
472 }),538 } },
473 .rm_sib_cc, .rm_rip_cc => try lower.emit(.none, mnem_cc(.cmov, inst.data.rx_cc.cc), &.{539 .rm_sib_cc, .rm_rip_cc => .{ .cc = inst.data.rx_cc.cc, .ops = .{
474 .{ .reg = inst.data.rx_cc.r },540 .{ .reg = inst.data.rx_cc.r },
475 .{ .mem = lower.mem(inst.ops, inst.data.rx_cc.payload) },541 .{ .mem = lower.mem(inst.ops, inst.data.rx_cc.payload) },
476 }),542 } },
477 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),543 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
544 };
545 switch (data.cc) {
546 else => |cc| try lower.emitInst(.none, mnem_cc(.cmov, cc), &data.ops),
547 .z_and_np => {
548 try lower.emitInst(.none, mnem_cc(.cmov, .nz), &.{ data.ops[1], data.ops[0] });
549 try lower.emitInst(.none, mnem_cc(.cmov, .np), &data.ops);
550 },
551 .nz_or_p => {
552 try lower.emitInst(.none, mnem_cc(.cmov, .nz), &data.ops);
553 try lower.emitInst(.none, mnem_cc(.cmov, .p), &data.ops);
554 },
478 }555 }
479}556}
480557
481fn mirSetcc(lower: *Lower, inst: Mir.Inst) Error!void {558fn mirSetcc(lower: *Lower, inst: Mir.Inst) Error!void {
482 switch (inst.ops) {559 const data: struct { cc: bits.Condition, ops: [2]Operand } = switch (inst.ops) {
483 .r_cc => try lower.emit(.none, mnem_cc(.set, inst.data.r_cc.cc), &.{560 .r_cc => .{ .cc = inst.data.r_cc.cc, .ops = .{
484 .{ .reg = inst.data.r_cc.r },561 .{ .reg = inst.data.r_cc.r },
485 }),562 .{ .reg = inst.data.r_cc.scratch },
486 .m_sib_cc, .m_rip_cc => try lower.emit(.none, mnem_cc(.set, inst.data.x_cc.cc), &.{563 } },
564 .m_sib_cc, .m_rip_cc => .{ .cc = inst.data.x_cc.cc, .ops = .{
487 .{ .mem = lower.mem(inst.ops, inst.data.x_cc.payload) },565 .{ .mem = lower.mem(inst.ops, inst.data.x_cc.payload) },
488 }),566 .{ .reg = inst.data.x_cc.scratch },
567 } },
489 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),568 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
569 };
570 switch (data.cc) {
571 else => |cc| try lower.emitInst(.none, mnem_cc(.set, cc), data.ops[0..1]),
572 .z_and_np => {
573 try lower.emitInst(.none, mnem_cc(.set, .z), data.ops[0..1]);
574 try lower.emitInst(.none, mnem_cc(.set, .np), data.ops[1..2]);
575 try lower.emitInst(.none, .@"and", data.ops[0..2]);
576 },
577 .nz_or_p => {
578 try lower.emitInst(.none, mnem_cc(.set, .nz), data.ops[0..1]);
579 try lower.emitInst(.none, mnem_cc(.set, .p), data.ops[1..2]);
580 try lower.emitInst(.none, .@"or", data.ops[0..2]);
581 },
490 }582 }
491}583}
492584
493fn mirPushPopRegisterList(lower: *Lower, inst: Mir.Inst, comptime mnemonic: Mnemonic) Error!void {585fn mirJcc(lower: *Lower, index: Mir.Inst.Index, inst: Mir.Inst) Error!void {
586 switch (inst.data.inst_cc.cc) {
587 else => |cc| try lower.emitInstWithReloc(.none, mnem_cc(.j, cc), &.{
588 .{ .imm = Immediate.s(0) },
589 }, .{ .inst = inst.data.inst_cc.inst }),
590 .z_and_np => {
591 try lower.emitInstWithReloc(.none, mnem_cc(.j, .nz), &.{
592 .{ .imm = Immediate.s(0) },
593 }, .{ .inst = index + 1 });
594 try lower.emitInstWithReloc(.none, mnem_cc(.j, .np), &.{
595 .{ .imm = Immediate.s(0) },
596 }, .{ .inst = inst.data.inst_cc.inst });
597 },
598 .nz_or_p => {
599 try lower.emitInstWithReloc(.none, mnem_cc(.j, .nz), &.{
600 .{ .imm = Immediate.s(0) },
601 }, .{ .inst = inst.data.inst_cc.inst });
602 try lower.emitInstWithReloc(.none, mnem_cc(.j, .p), &.{
603 .{ .imm = Immediate.s(0) },
604 }, .{ .inst = inst.data.inst_cc.inst });
605 },
606 }
607}
608
609fn mirRegisterList(lower: *Lower, comptime mnemonic: Mnemonic, inst: Mir.Inst) Error!void {
494 const reg_list = Mir.RegisterList.fromInt(inst.data.payload);610 const reg_list = Mir.RegisterList.fromInt(inst.data.payload);
495 const callee_preserved_regs = abi.getCalleePreservedRegs(lower.target.*);611 const callee_preserved_regs = abi.getCalleePreservedRegs(lower.target.*);
496 var it = reg_list.iterator(.{ .direction = switch (mnemonic) {612 var it = reg_list.iterator(.{ .direction = switch (mnemonic) {
...@@ -498,24 +614,20 @@ fn mirPushPopRegisterList(lower: *Lower, inst: Mir.Inst, comptime mnemonic: Mnem...@@ -498,24 +614,20 @@ fn mirPushPopRegisterList(lower: *Lower, inst: Mir.Inst, comptime mnemonic: Mnem
498 .pop => .forward,614 .pop => .forward,
499 else => unreachable,615 else => unreachable,
500 } });616 } });
501 while (it.next()) |i| try lower.emit(.none, mnemonic, &.{.{ .reg = callee_preserved_regs[i] }});617 while (it.next()) |i| try lower.emitInst(.none, mnemonic, &.{.{ .reg = callee_preserved_regs[i] }});
502}618}
503619
504fn mirLeaLinker(lower: *Lower, inst: Mir.Inst) Error!void {620fn mirLinker(lower: *Lower, mnemonic: Mnemonic, inst: Mir.Inst) Error!void {
505 const metadata = lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data;621 const reloc = lower.mir.extraData(Mir.Reloc, inst.data.rx.payload).data;
506 const reg = @intToEnum(Register, metadata.reg);622 try lower.emitInstWithReloc(.none, mnemonic, &.{
507 try lower.emit(.none, .lea, &.{623 .{ .reg = inst.data.rx.r },
508 .{ .reg = reg },624 .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(inst.data.rx.r.bitSize()), 0) },
509 .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) },625 }, switch (inst.ops) {
510 });626 .got_reloc => .{ .linker_got = reloc },
511}627 .direct_reloc => .{ .linker_direct = reloc },
512628 .import_reloc => .{ .linker_import = reloc },
513fn mirMovLinker(lower: *Lower, inst: Mir.Inst) Error!void {629 .tlv_reloc => .{ .linker_tlv = reloc },
514 const metadata = lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data;630 else => unreachable,
515 const reg = @intToEnum(Register, metadata.reg);
516 try lower.emit(.none, .mov, &.{
517 .{ .reg = reg },
518 .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) },
519 });631 });
520}632}
521633
src/arch/x86_64/Mir.zig+21-13
...@@ -434,6 +434,12 @@ pub const Inst = struct {...@@ -434,6 +434,12 @@ pub const Inst = struct {
434 /// Register, memory (SIB), immediate (byte) operands.434 /// Register, memory (SIB), immediate (byte) operands.
435 /// Uses `rix` payload with extra data of type `MemorySib`.435 /// Uses `rix` payload with extra data of type `MemorySib`.
436 rmi_sib,436 rmi_sib,
437 /// Register, register, memory (RIP), immediate (byte) operands.
438 /// Uses `rrix` payload with extra data of type `MemoryRip`.
439 rrmi_rip,
440 /// Register, register, memory (SIB), immediate (byte) operands.
441 /// Uses `rrix` payload with extra data of type `MemorySib`.
442 rrmi_sib,
437 /// Register, memory (RIP), immediate (byte) operands.443 /// Register, memory (RIP), immediate (byte) operands.
438 /// Uses `rix` payload with extra data of type `MemoryRip`.444 /// Uses `rix` payload with extra data of type `MemoryRip`.
439 rmi_rip,445 rmi_rip,
...@@ -524,16 +530,16 @@ pub const Inst = struct {...@@ -524,16 +530,16 @@ pub const Inst = struct {
524 /// Uses `reloc` payload.530 /// Uses `reloc` payload.
525 reloc,531 reloc,
526 /// Linker relocation - GOT indirection.532 /// Linker relocation - GOT indirection.
527 /// Uses `payload` payload with extra data of type `LeaRegisterReloc`.533 /// Uses `rx` payload with extra data of type `Reloc`.
528 got_reloc,534 got_reloc,
529 /// Linker relocation - direct reference.535 /// Linker relocation - direct reference.
530 /// Uses `payload` payload with extra data of type `LeaRegisterReloc`.536 /// Uses `rx` payload with extra data of type `Reloc`.
531 direct_reloc,537 direct_reloc,
532 /// Linker relocation - imports table indirection (binding).538 /// Linker relocation - imports table indirection (binding).
533 /// Uses `payload` payload with extra data of type `LeaRegisterReloc`.539 /// Uses `rx` payload with extra data of type `Reloc`.
534 import_reloc,540 import_reloc,
535 /// Linker relocation - threadlocal variable via GOT indirection.541 /// Linker relocation - threadlocal variable via GOT indirection.
536 /// Uses `payload` payload with extra data of type `LeaRegisterReloc`.542 /// Uses `rx` payload with extra data of type `Reloc`.
537 tlv_reloc,543 tlv_reloc,
538 };544 };
539545
...@@ -567,12 +573,14 @@ pub const Inst = struct {...@@ -567,12 +573,14 @@ pub const Inst = struct {
567 },573 },
568 /// Condition code (CC), followed by custom payload found in extra.574 /// Condition code (CC), followed by custom payload found in extra.
569 x_cc: struct {575 x_cc: struct {
576 scratch: Register,
570 cc: bits.Condition,577 cc: bits.Condition,
571 payload: u32,578 payload: u32,
572 },579 },
573 /// Register with condition code (CC).580 /// Register with condition code (CC).
574 r_cc: struct {581 r_cc: struct {
575 r: Register,582 r: Register,
583 scratch: Register,
576 cc: bits.Condition,584 cc: bits.Condition,
577 },585 },
578 /// Register, register with condition code (CC).586 /// Register, register with condition code (CC).
...@@ -614,6 +622,13 @@ pub const Inst = struct {...@@ -614,6 +622,13 @@ pub const Inst = struct {
614 i: u8,622 i: u8,
615 payload: u32,623 payload: u32,
616 },624 },
625 /// Register, register, byte immediate, followed by Custom payload found in extra.
626 rrix: struct {
627 r1: Register,
628 r2: Register,
629 i: u8,
630 payload: u32,
631 },
617 /// String instruction prefix and width.632 /// String instruction prefix and width.
618 string: struct {633 string: struct {
619 repeat: bits.StringRepeat,634 repeat: bits.StringRepeat,
...@@ -622,12 +637,7 @@ pub const Inst = struct {...@@ -622,12 +637,7 @@ pub const Inst = struct {
622 /// Relocation for the linker where:637 /// Relocation for the linker where:
623 /// * `atom_index` is the index of the source638 /// * `atom_index` is the index of the source
624 /// * `sym_index` is the index of the target639 /// * `sym_index` is the index of the target
625 relocation: struct {640 relocation: Reloc,
626 /// Index of the containing atom.
627 atom_index: u32,
628 /// Index into the linker's symbol table.
629 sym_index: u32,
630 },
631 /// Debug line and column position641 /// Debug line and column position
632 line_column: struct {642 line_column: struct {
633 line: u32,643 line: u32,
...@@ -646,9 +656,7 @@ pub const Inst = struct {...@@ -646,9 +656,7 @@ pub const Inst = struct {
646 }656 }
647};657};
648658
649pub const LeaRegisterReloc = struct {659pub const Reloc = struct {
650 /// Destination register.
651 reg: u32,
652 /// Index of the containing atom.660 /// Index of the containing atom.
653 atom_index: u32,661 atom_index: u32,
654 /// Index into the linker's symbol table.662 /// Index into the linker's symbol table.
src/arch/x86_64/bits.zig+9
...@@ -72,6 +72,12 @@ pub const Condition = enum(u5) {...@@ -72,6 +72,12 @@ pub const Condition = enum(u5) {
72 /// zero72 /// zero
73 z,73 z,
7474
75 // Pseudo conditions
76 /// zero and not parity
77 z_and_np,
78 /// not zero or parity
79 nz_or_p,
80
75 /// Converts a std.math.CompareOperator into a condition flag,81 /// Converts a std.math.CompareOperator into a condition flag,
76 /// i.e. returns the condition that is true iff the result of the82 /// i.e. returns the condition that is true iff the result of the
77 /// comparison is true. Assumes signed comparison83 /// comparison is true. Assumes signed comparison
...@@ -143,6 +149,9 @@ pub const Condition = enum(u5) {...@@ -143,6 +149,9 @@ pub const Condition = enum(u5) {
143 .po => .pe,149 .po => .pe,
144 .s => .ns,150 .s => .ns,
145 .z => .nz,151 .z => .nz,
152
153 .z_and_np => .nz_or_p,
154 .nz_or_p => .z_and_np,
146 };155 };
147 }156 }
148};157};
src/arch/x86_64/encoder.zig+2-2
...@@ -245,9 +245,9 @@ pub const Instruction = struct {...@@ -245,9 +245,9 @@ pub const Instruction = struct {
245 },245 },
246 .mem => |mem| {246 .mem => |mem| {
247 const op = switch (data.op_en) {247 const op = switch (data.op_en) {
248 .m, .mi, .m1, .mc => .none,248 .m, .mi, .m1, .mc, .vmi => .none,
249 .mr, .mri, .mrc => inst.ops[1],249 .mr, .mri, .mrc => inst.ops[1],
250 .rm, .rmi => inst.ops[0],250 .rm, .rmi, .rvm, .rvmi => inst.ops[0],
251 else => unreachable,251 else => unreachable,
252 };252 };
253 try encodeMemory(enc, mem, op, encoder);253 try encodeMemory(enc, mem, op, encoder);
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/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);