authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-10-29 15:17:03-04:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-10-30 09:31:30+00:00
log402c14f86a97f47ca429565fddb7ffca5c08d873
treeee2b6f3f8dc7dd86f81c10d37840375de3d1c819
parent0dde70ef763d7d21ea2fe703deb253a9ae59cf72
signaturelock-open Commit is signed but in an unrecognized format.

aarch64: implement optional comparisons


8 files changed, 384 insertions(+), 291 deletions(-)

src/codegen/aarch64/Disassemble.zig+34-6
...@@ -74,10 +74,10 @@ pub fn printInstruction(dis: Disassemble, inst: aarch64.encoding.Instruction, wr...@@ -74,10 +74,10 @@ pub fn printInstruction(dis: Disassemble, inst: aarch64.encoding.Instruction, wr
74 dis.operands_separator,74 dis.operands_separator,
75 imm12,75 imm12,
76 });76 });
77 return if (!elide_shift) writer.print("{s}{f} #{s}", .{77 return if (!elide_shift) writer.print("{s}{f} #{t}", .{
78 dis.operands_separator,78 dis.operands_separator,
79 fmtCase(.lsl, dis.case),79 fmtCase(.lsl, dis.case),
80 @tagName(sh),80 sh,
81 });81 });
82 },82 },
83 .add_subtract_immediate_with_tags => |add_subtract_immediate_with_tags| {83 .add_subtract_immediate_with_tags => |add_subtract_immediate_with_tags| {
...@@ -176,10 +176,10 @@ pub fn printInstruction(dis: Disassemble, inst: aarch64.encoding.Instruction, wr...@@ -176,10 +176,10 @@ pub fn printInstruction(dis: Disassemble, inst: aarch64.encoding.Instruction, wr
176 dis.operands_separator,176 dis.operands_separator,
177 imm16,177 imm16,
178 });178 });
179 return if (!elide_shift) writer.print("{s}{f} #{s}", .{179 return if (!elide_shift) writer.print("{s}{f} #{t}", .{
180 dis.operands_separator,180 dis.operands_separator,
181 fmtCase(.lsl, dis.case),181 fmtCase(.lsl, dis.case),
182 @tagName(hw),182 hw,
183 });183 });
184 },184 },
185 .bitfield => |bitfield| {185 .bitfield => |bitfield| {
...@@ -833,8 +833,36 @@ pub fn printInstruction(dis: Disassemble, inst: aarch64.encoding.Instruction, wr...@@ -833,8 +833,36 @@ pub fn printInstruction(dis: Disassemble, inst: aarch64.encoding.Instruction, wr
833 },833 },
834 .rotate_right_into_flags => {},834 .rotate_right_into_flags => {},
835 .evaluate_into_flags => {},835 .evaluate_into_flags => {},
836 .conditional_compare_register => {},836 .conditional_compare_register => |conditional_compare_register| {
837 .conditional_compare_immediate => {},837 const group = conditional_compare_register.group;
838 const sf = group.sf;
839 return writer.print("{f}{s}{f}{s}{f}{s}#0x{x}{s}{f}", .{
840 fmtCase(group.op, dis.case),
841 dis.mnemonic_operands_separator,
842 group.Rn.decode(.{}).general(sf).fmtCase(dis.case),
843 dis.operands_separator,
844 group.Rm.decode(.{}).general(sf).fmtCase(dis.case),
845 dis.operands_separator,
846 @as(u4, @bitCast(group.nzcv)),
847 dis.operands_separator,
848 fmtCase(group.cond, dis.case),
849 });
850 },
851 .conditional_compare_immediate => |conditional_compare_immediate| {
852 const group = conditional_compare_immediate.group;
853 const sf = group.sf;
854 return writer.print("{f}{s}{f}{s}#0x{x}{s}#0x{x}{s}{f}", .{
855 fmtCase(group.op, dis.case),
856 dis.mnemonic_operands_separator,
857 group.Rn.decode(.{}).general(sf).fmtCase(dis.case),
858 dis.operands_separator,
859 group.imm5,
860 dis.operands_separator,
861 @as(u4, @bitCast(group.nzcv)),
862 dis.operands_separator,
863 fmtCase(group.cond, dis.case),
864 });
865 },
838 .conditional_select => |conditional_select| {866 .conditional_select => |conditional_select| {
839 const decoded = conditional_select.decode();867 const decoded = conditional_select.decode();
840 if (decoded == .unallocated) break :unallocated;868 if (decoded == .unallocated) break :unallocated;
src/codegen/aarch64/Mir.zig+2-2
...@@ -136,7 +136,7 @@ pub fn emit(...@@ -136,7 +136,7 @@ pub fn emit(
136 mf.getZigObject().?.getOrCreateMetadataForLazySymbol(mf, pt, lazy_reloc.symbol) catch |err|136 mf.getZigObject().?.getOrCreateMetadataForLazySymbol(mf, pt, lazy_reloc.symbol) catch |err|
137 return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})137 return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})
138 else138 else
139 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),139 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {t}", .{lf.tag}),
140 mir.body[lazy_reloc.reloc.label],140 mir.body[lazy_reloc.reloc.label],
141 body_end - Instruction.size * (1 + lazy_reloc.reloc.label),141 body_end - Instruction.size * (1 + lazy_reloc.reloc.label),
142 lazy_reloc.reloc.addend,142 lazy_reloc.reloc.addend,
...@@ -150,7 +150,7 @@ pub fn emit(...@@ -150,7 +150,7 @@ pub fn emit(
150 else if (lf.cast(.macho)) |mf|150 else if (lf.cast(.macho)) |mf|
151 try mf.getGlobalSymbol(std.mem.span(global_reloc.name), null)151 try mf.getGlobalSymbol(std.mem.span(global_reloc.name), null)
152 else152 else
153 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),153 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {t}", .{lf.tag}),
154 mir.body[global_reloc.reloc.label],154 mir.body[global_reloc.reloc.label],
155 body_end - Instruction.size * (1 + global_reloc.reloc.label),155 body_end - Instruction.size * (1 + global_reloc.reloc.label),
156 global_reloc.reloc.addend,156 global_reloc.reloc.addend,
src/codegen/aarch64/Select.zig+348-270
...@@ -961,7 +961,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -961,7 +961,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
961 .inst_index = undefined,961 .inst_index = undefined,
962 };962 };
963 air_tag: switch (air.next().?) {963 air_tag: switch (air.next().?) {
964 else => |air_tag| return isel.fail("unimplemented {s}", .{@tagName(air_tag)}),964 else => |air_tag| return isel.fail("unimplemented {t}", .{air_tag}),
965 .arg => {965 .arg => {
966 const arg_vi = isel.live_values.fetchRemove(air.inst_index).?.value;966 const arg_vi = isel.live_values.fetchRemove(air.inst_index).?.value;
967 defer arg_vi.deref(isel);967 defer arg_vi.deref(isel);
...@@ -1117,12 +1117,12 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -1117,12 +1117,12 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
11171117
1118 const bin_op = air.data(air.inst_index).bin_op;1118 const bin_op = air.data(air.inst_index).bin_op;
1119 const ty = isel.air.typeOf(bin_op.lhs, ip);1119 const ty = isel.air.typeOf(bin_op.lhs, ip);
1120 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });1120 if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) });
1121 const int_info = ty.intInfo(zcu);1121 const int_info = ty.intInfo(zcu);
1122 switch (int_info.bits) {1122 switch (int_info.bits) {
1123 0 => unreachable,1123 0 => unreachable,
1124 32, 64 => |bits| switch (int_info.signedness) {1124 32, 64 => |bits| switch (int_info.signedness) {
1125 .signed => return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),1125 .signed => return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }),
1126 .unsigned => {1126 .unsigned => {
1127 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;1127 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1128 const lhs_vi = try isel.use(bin_op.lhs);1128 const lhs_vi = try isel.use(bin_op.lhs);
...@@ -1160,7 +1160,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -1160,7 +1160,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
1160 try lhs_mat.finish(isel);1160 try lhs_mat.finish(isel);
1161 },1161 },
1162 },1162 },
1163 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),1163 else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }),
1164 }1164 }
1165 }1165 }
1166 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;1166 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
...@@ -1172,7 +1172,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -1172,7 +1172,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
1172 const bin_op = air.data(air.inst_index).bin_op;1172 const bin_op = air.data(air.inst_index).bin_op;
1173 const ty = isel.air.typeOf(bin_op.lhs, ip);1173 const ty = isel.air.typeOf(bin_op.lhs, ip);
1174 if (!ty.isRuntimeFloat()) {1174 if (!ty.isRuntimeFloat()) {
1175 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });1175 if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) });
1176 const int_info = ty.intInfo(zcu);1176 const int_info = ty.intInfo(zcu);
1177 switch (int_info.bits) {1177 switch (int_info.bits) {
1178 0 => unreachable,1178 0 => unreachable,
...@@ -1318,7 +1318,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -1318,7 +1318,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
1318 try rhs_lo64_mat.finish(isel);1318 try rhs_lo64_mat.finish(isel);
1319 try lhs_lo64_mat.finish(isel);1319 try lhs_lo64_mat.finish(isel);
1320 },1320 },
1321 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),1321 else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }),
1322 }1322 }
1323 } else switch (ty.floatBits(isel.target)) {1323 } else switch (ty.floatBits(isel.target)) {
1324 else => unreachable,1324 else => unreachable,
...@@ -1421,7 +1421,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -1421,7 +1421,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
14211421
1422 const bin_op = air.data(air.inst_index).bin_op;1422 const bin_op = air.data(air.inst_index).bin_op;
1423 const ty = isel.air.typeOf(bin_op.lhs, ip);1423 const ty = isel.air.typeOf(bin_op.lhs, ip);
1424 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });1424 if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) });
1425 const int_info = ty.intInfo(zcu);1425 const int_info = ty.intInfo(zcu);
1426 switch (int_info.signedness) {1426 switch (int_info.signedness) {
1427 .signed => switch (int_info.bits) {1427 .signed => switch (int_info.bits) {
...@@ -1443,7 +1443,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -1443,7 +1443,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
1443 try rhs_mat.finish(isel);1443 try rhs_mat.finish(isel);
1444 try lhs_mat.finish(isel);1444 try lhs_mat.finish(isel);
1445 },1445 },
1446 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),1446 else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }),
1447 },1447 },
1448 .unsigned => switch (int_info.bits) {1448 .unsigned => switch (int_info.bits) {
1449 0 => unreachable,1449 0 => unreachable,
...@@ -1545,8 +1545,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -1545,8 +1545,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
1545 try rhs_mat.finish(isel);1545 try rhs_mat.finish(isel);
1546 try lhs_mat.finish(isel);1546 try lhs_mat.finish(isel);
1547 },1547 },
1548 65...128 => return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),1548 65...128 => return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }),
1549 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),1549 else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }),
1550 },1550 },
1551 }1551 }
1552 }1552 }
...@@ -1558,7 +1558,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -1558,7 +1558,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
15581558
1559 const bin_op = air.data(air.inst_index).bin_op;1559 const bin_op = air.data(air.inst_index).bin_op;
1560 const ty = isel.air.typeOf(bin_op.lhs, ip);1560 const ty = isel.air.typeOf(bin_op.lhs, ip);
1561 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });1561 if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) });
1562 const int_info = ty.intInfo(zcu);1562 const int_info = ty.intInfo(zcu);
1563 switch (int_info.bits) {1563 switch (int_info.bits) {
1564 0 => unreachable,1564 0 => unreachable,
...@@ -1784,7 +1784,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -1784,7 +1784,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
1784 try rhs_mat.finish(isel);1784 try rhs_mat.finish(isel);
1785 try lhs_mat.finish(isel);1785 try lhs_mat.finish(isel);
1786 },1786 },
1787 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),1787 else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }),
1788 }1788 }
1789 }1789 }
1790 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;1790 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
...@@ -1897,7 +1897,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -1897,7 +1897,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
1897 const bin_op = air.data(air.inst_index).bin_op;1897 const bin_op = air.data(air.inst_index).bin_op;
1898 const ty = isel.air.typeOf(bin_op.lhs, ip);1898 const ty = isel.air.typeOf(bin_op.lhs, ip);
1899 if (!ty.isRuntimeFloat()) {1899 if (!ty.isRuntimeFloat()) {
1900 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });1900 if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) });
1901 const int_info = ty.intInfo(zcu);1901 const int_info = ty.intInfo(zcu);
1902 switch (int_info.bits) {1902 switch (int_info.bits) {
1903 0 => unreachable,1903 0 => unreachable,
...@@ -1970,7 +1970,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -1970,7 +1970,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
1970 else => unreachable,1970 else => unreachable,
1971 .div_trunc, .div_exact => {},1971 .div_trunc, .div_exact => {},
1972 .div_floor => switch (int_info.signedness) {1972 .div_floor => switch (int_info.signedness) {
1973 .signed => return isel.fail("unimplemented {s}", .{@tagName(air_tag)}),1973 .signed => return isel.fail("unimplemented {t}", .{air_tag}),
1974 .unsigned => {},1974 .unsigned => {},
1975 },1975 },
1976 }1976 }
...@@ -2012,7 +2012,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -2012,7 +2012,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
2012 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);2012 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
2013 try call.finishParams(isel);2013 try call.finishParams(isel);
2014 },2014 },
2015 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),2015 else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }),
2016 }2016 }
2017 } else switch (ty.floatBits(isel.target)) {2017 } else switch (ty.floatBits(isel.target)) {
2018 else => unreachable,2018 else => unreachable,
...@@ -2169,9 +2169,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -2169,9 +2169,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
2169 const bin_op = air.data(air.inst_index).bin_op;2169 const bin_op = air.data(air.inst_index).bin_op;
2170 const ty = isel.air.typeOf(bin_op.lhs, ip);2170 const ty = isel.air.typeOf(bin_op.lhs, ip);
2171 if (!ty.isRuntimeFloat()) {2171 if (!ty.isRuntimeFloat()) {
2172 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });2172 if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) });
2173 const int_info = ty.intInfo(zcu);2173 const int_info = ty.intInfo(zcu);
2174 if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });2174 if (int_info.bits > 64) return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) });
21752175
2176 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;2176 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
2177 const lhs_vi = try isel.use(bin_op.lhs);2177 const lhs_vi = try isel.use(bin_op.lhs);
...@@ -2494,9 +2494,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -2494,9 +2494,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
2494 const bin_op = air.data(air.inst_index).bin_op;2494 const bin_op = air.data(air.inst_index).bin_op;
2495 const ty = isel.air.typeOf(bin_op.lhs, ip);2495 const ty = isel.air.typeOf(bin_op.lhs, ip);
2496 if (!ty.isRuntimeFloat()) {2496 if (!ty.isRuntimeFloat()) {
2497 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });2497 if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) });
2498 const int_info = ty.intInfo(zcu);2498 const int_info = ty.intInfo(zcu);
2499 if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });2499 if (int_info.bits > 64) return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) });
25002500
2501 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;2501 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
2502 const lhs_vi = try isel.use(bin_op.lhs);2502 const lhs_vi = try isel.use(bin_op.lhs);
...@@ -2920,8 +2920,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -2920,8 +2920,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
2920 else if (ty.isAbiInt(zcu))2920 else if (ty.isAbiInt(zcu))
2921 ty.intInfo(zcu)2921 ty.intInfo(zcu)
2922 else2922 else
2923 return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });2923 return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) });
2924 if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });2924 if (int_info.bits > 128) return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) });
29252925
2926 const lhs_vi = try isel.use(bin_op.lhs);2926 const lhs_vi = try isel.use(bin_op.lhs);
2927 const rhs_vi = try isel.use(bin_op.rhs);2927 const rhs_vi = try isel.use(bin_op.rhs);
...@@ -2968,7 +2968,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -2968,7 +2968,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
29682968
2969 const bin_op = air.data(air.inst_index).bin_op;2969 const bin_op = air.data(air.inst_index).bin_op;
2970 const ty = isel.air.typeOf(bin_op.lhs, ip);2970 const ty = isel.air.typeOf(bin_op.lhs, ip);
2971 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });2971 if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) });
2972 const int_info = ty.intInfo(zcu);2972 const int_info = ty.intInfo(zcu);
2973 switch (int_info.bits) {2973 switch (int_info.bits) {
2974 0 => unreachable,2974 0 => unreachable,
...@@ -3161,7 +3161,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3161,7 +3161,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3161 try lhs_hi64_mat.finish(isel);3161 try lhs_hi64_mat.finish(isel);
3162 break :unused;3162 break :unused;
3163 },3163 },
3164 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),3164 else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }),
3165 }3165 }
3166 }3166 }
3167 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;3167 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
...@@ -3174,10 +3174,10 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3174,10 +3174,10 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3174 const ty = ty_op.ty.toType();3174 const ty = ty_op.ty.toType();
3175 const int_info: std.builtin.Type.Int = int_info: {3175 const int_info: std.builtin.Type.Int = int_info: {
3176 if (ty_op.ty == .bool_type) break :int_info .{ .signedness = .unsigned, .bits = 1 };3176 if (ty_op.ty == .bool_type) break :int_info .{ .signedness = .unsigned, .bits = 1 };
3177 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });3177 if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) });
3178 break :int_info ty.intInfo(zcu);3178 break :int_info ty.intInfo(zcu);
3179 };3179 };
3180 if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });3180 if (int_info.bits > 128) return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) });
31813181
3182 const src_vi = try isel.use(ty_op.operand);3182 const src_vi = try isel.use(ty_op.operand);
3183 var offset = res_vi.value.size(isel);3183 var offset = res_vi.value.size(isel);
...@@ -3302,7 +3302,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3302,7 +3302,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3302 }3302 }
3303 },3303 },
3304 128 => try dst_vi.value.move(isel, ty_op.operand),3304 128 => try dst_vi.value.move(isel, ty_op.operand),
3305 else => return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }),3305 else => return isel.fail("bad {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) }),
3306 }3306 }
3307 } else if ((dst_ty.isPtrAtRuntime(zcu) or dst_ty.isAbiInt(zcu)) and (src_ty.isPtrAtRuntime(zcu) or src_ty.isAbiInt(zcu))) {3307 } else if ((dst_ty.isPtrAtRuntime(zcu) or dst_ty.isAbiInt(zcu)) and (src_ty.isPtrAtRuntime(zcu) or src_ty.isAbiInt(zcu))) {
3308 try dst_vi.value.move(isel, ty_op.operand);3308 try dst_vi.value.move(isel, ty_op.operand);
...@@ -3313,7 +3313,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3313,7 +3313,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3313 src_ty.errorUnionSet(zcu).hasRuntimeBitsIgnoreComptime(zcu));3313 src_ty.errorUnionSet(zcu).hasRuntimeBitsIgnoreComptime(zcu));
3314 if (dst_ty.errorUnionPayload(zcu).toIntern() == src_ty.errorUnionPayload(zcu).toIntern()) {3314 if (dst_ty.errorUnionPayload(zcu).toIntern() == src_ty.errorUnionPayload(zcu).toIntern()) {
3315 try dst_vi.value.move(isel, ty_op.operand);3315 try dst_vi.value.move(isel, ty_op.operand);
3316 } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });3316 } else return isel.fail("bad {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) });
3317 } else if (dst_tag == .float and src_tag == .float) {3317 } else if (dst_tag == .float and src_tag == .float) {
3318 assert(dst_ty.floatBits(isel.target) == src_ty.floatBits(isel.target));3318 assert(dst_ty.floatBits(isel.target) == src_ty.floatBits(isel.target));
3319 try dst_vi.value.move(isel, ty_op.operand);3319 try dst_vi.value.move(isel, ty_op.operand);
...@@ -3483,7 +3483,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3483,7 +3483,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3483 try call.paramAddress(isel, src_vi, .r1);3483 try call.paramAddress(isel, src_vi, .r1);
3484 try call.paramAddress(isel, dst_vi.value, .r0);3484 try call.paramAddress(isel, dst_vi.value, .r0);
3485 try call.finishParams(isel);3485 try call.finishParams(isel);
3486 } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });3486 } else return isel.fail("bad {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) });
3487 } else if (dst_tag == .array and dst_ty.childType(zcu).isAbiInt(zcu) and src_ty.isAbiInt(zcu)) {3487 } else if (dst_tag == .array and dst_ty.childType(zcu).isAbiInt(zcu) and src_ty.isAbiInt(zcu)) {
3488 const dst_child_int_info = dst_ty.childType(zcu).intInfo(zcu);3488 const dst_child_int_info = dst_ty.childType(zcu).intInfo(zcu);
3489 const src_int_info = src_ty.intInfo(zcu);3489 const src_int_info = src_ty.intInfo(zcu);
...@@ -3510,8 +3510,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3510,8 +3510,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3510 try call.paramAddress(isel, src_vi, .r1);3510 try call.paramAddress(isel, src_vi, .r1);
3511 try call.paramAddress(isel, dst_vi.value, .r0);3511 try call.paramAddress(isel, dst_vi.value, .r0);
3512 try call.finishParams(isel);3512 try call.finishParams(isel);
3513 } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });3513 } else return isel.fail("bad {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) });
3514 } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });3514 } else return isel.fail("bad {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) });
3515 }3515 }
3516 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;3516 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3517 },3517 },
...@@ -3737,7 +3737,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3737,7 +3737,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
37373737
3738 const ty_op = air.data(air.inst_index).ty_op;3738 const ty_op = air.data(air.inst_index).ty_op;
3739 const ty = isel.air.typeOf(ty_op.operand, ip);3739 const ty = isel.air.typeOf(ty_op.operand, ip);
3740 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });3740 if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) });
3741 const int_info = ty.intInfo(zcu);3741 const int_info = ty.intInfo(zcu);
3742 switch (int_info.bits) {3742 switch (int_info.bits) {
3743 0 => unreachable,3743 0 => unreachable,
...@@ -3769,7 +3769,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3769,7 +3769,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3769 try src_hi64_mat.finish(isel);3769 try src_hi64_mat.finish(isel);
3770 try src_lo64_mat.finish(isel);3770 try src_lo64_mat.finish(isel);
3771 },3771 },
3772 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),3772 else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }),
3773 }3773 }
3774 }3774 }
3775 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;3775 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
...@@ -3780,7 +3780,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3780,7 +3780,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
37803780
3781 const ty_op = air.data(air.inst_index).ty_op;3781 const ty_op = air.data(air.inst_index).ty_op;
3782 const ty = isel.air.typeOf(ty_op.operand, ip);3782 const ty = isel.air.typeOf(ty_op.operand, ip);
3783 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });3783 if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) });
3784 const int_info = ty.intInfo(zcu);3784 const int_info = ty.intInfo(zcu);
3785 switch (int_info.bits) {3785 switch (int_info.bits) {
3786 0 => unreachable,3786 0 => unreachable,
...@@ -3812,7 +3812,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3812,7 +3812,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3812 try src_hi64_mat.finish(isel);3812 try src_hi64_mat.finish(isel);
3813 try src_lo64_mat.finish(isel);3813 try src_lo64_mat.finish(isel);
3814 },3814 },
3815 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),3815 else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }),
3816 }3816 }
3817 }3817 }
3818 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;3818 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
...@@ -3823,9 +3823,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3823,9 +3823,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
38233823
3824 const ty_op = air.data(air.inst_index).ty_op;3824 const ty_op = air.data(air.inst_index).ty_op;
3825 const ty = isel.air.typeOf(ty_op.operand, ip);3825 const ty = isel.air.typeOf(ty_op.operand, ip);
3826 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });3826 if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) });
3827 const int_info = ty.intInfo(zcu);3827 const int_info = ty.intInfo(zcu);
3828 if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });3828 if (int_info.bits > 64) return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) });
38293829
3830 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;3830 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3831 const src_vi = try isel.use(ty_op.operand);3831 const src_vi = try isel.use(ty_op.operand);
...@@ -3877,9 +3877,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3877,9 +3877,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
38773877
3878 const ty_op = air.data(air.inst_index).ty_op;3878 const ty_op = air.data(air.inst_index).ty_op;
3879 const ty = ty_op.ty.toType();3879 const ty = ty_op.ty.toType();
3880 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });3880 if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) });
3881 const int_info = ty.intInfo(zcu);3881 const int_info = ty.intInfo(zcu);
3882 if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });3882 if (int_info.bits > 64) return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) });
38833883
3884 if (int_info.bits == 8) break :unused try res_vi.value.move(isel, ty_op.operand);3884 if (int_info.bits == 8) break :unused try res_vi.value.move(isel, ty_op.operand);
3885 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;3885 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
...@@ -3941,9 +3941,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3941,9 +3941,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
39413941
3942 const ty_op = air.data(air.inst_index).ty_op;3942 const ty_op = air.data(air.inst_index).ty_op;
3943 const ty = ty_op.ty.toType();3943 const ty = ty_op.ty.toType();
3944 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });3944 if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) });
3945 const int_info = ty.intInfo(zcu);3945 const int_info = ty.intInfo(zcu);
3946 if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });3946 if (int_info.bits > 64) return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) });
39473947
3948 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;3948 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3949 const src_vi = try isel.use(ty_op.operand);3949 const src_vi = try isel.use(ty_op.operand);
...@@ -4244,7 +4244,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -4244,7 +4244,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
4244 const ty_op = air.data(air.inst_index).ty_op;4244 const ty_op = air.data(air.inst_index).ty_op;
4245 const ty = ty_op.ty.toType();4245 const ty = ty_op.ty.toType();
4246 if (!ty.isRuntimeFloat()) {4246 if (!ty.isRuntimeFloat()) {
4247 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });4247 if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) });
4248 switch (ty.intInfo(zcu).bits) {4248 switch (ty.intInfo(zcu).bits) {
4249 0 => unreachable,4249 0 => unreachable,
4250 1...32 => {4250 1...32 => {
...@@ -4306,7 +4306,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -4306,7 +4306,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
4306 try src_lo64_mat.finish(isel);4306 try src_lo64_mat.finish(isel);
4307 try src_hi64_mat.finish(isel);4307 try src_hi64_mat.finish(isel);
4308 },4308 },
4309 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),4309 else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }),
4310 }4310 }
4311 } else switch (ty.floatBits(isel.target)) {4311 } else switch (ty.floatBits(isel.target)) {
4312 else => unreachable,4312 else => unreachable,
...@@ -4465,216 +4465,61 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -4465,216 +4465,61 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
4465 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {4465 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
4466 defer res_vi.value.deref(isel);4466 defer res_vi.value.deref(isel);
44674467
4468 var bin_op = air.data(air.inst_index).bin_op;4468 const bin_op = air.data(air.inst_index).bin_op;
4469 const ty = isel.air.typeOf(bin_op.lhs, ip);4469 const ty = isel.air.typeOf(bin_op.lhs, ip);
4470 if (!ty.isRuntimeFloat()) {4470 switch (ip.indexToKey(ty.toIntern())) {
4471 const int_info: std.builtin.Type.Int = if (ty.toIntern() == .bool_type)4471 else => {},
4472 .{ .signedness = .unsigned, .bits = 1 }4472 .opt_type => |payload_ty| switch (air_tag) {
4473 else if (ty.isAbiInt(zcu))
4474 ty.intInfo(zcu)
4475 else if (ty.isPtrAtRuntime(zcu))
4476 .{ .signedness = .unsigned, .bits = 64 }
4477 else
4478 return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
4479 if (int_info.bits > 256) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
4480
4481 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4482 try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(cond: switch (air_tag) {
4483 else => unreachable,4473 else => unreachable,
4484 .cmp_lt => switch (int_info.signedness) {4474 .cmp_eq, .cmp_neq => if (!ty.optionalReprIsPayload(zcu)) {
4485 .signed => .lt,4475 const lhs_vi = try isel.use(bin_op.lhs);
4486 .unsigned => .lo,4476 const rhs_vi = try isel.use(bin_op.rhs);
4487 },4477 const payload_size = ZigType.abiSize(.fromInterned(payload_ty), zcu);
4488 .cmp_lte => switch (int_info.bits) {4478 var lhs_payload_part_it = lhs_vi.field(ty, 0, payload_size);
4489 else => unreachable,4479 const lhs_payload_part_vi = try lhs_payload_part_it.only(isel);
4490 1...64 => switch (int_info.signedness) {4480 var rhs_payload_part_it = rhs_vi.field(ty, 0, payload_size);
4491 .signed => .le,4481 const rhs_payload_part_vi = try rhs_payload_part_it.only(isel);
4492 .unsigned => .ls,4482 const cmp_info = try isel.cmp(
4493 },4483 try res_vi.value.defReg(isel) orelse break :unused,
4494 65...128 => {4484 .fromInterned(payload_ty),
4495 std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs);4485 lhs_payload_part_vi.?,
4496 continue :cond .cmp_gte;4486 air_tag.toCmpOp().?,
4497 },4487 rhs_payload_part_vi.?,
4498 },4488 );
4499 .cmp_eq => .eq,4489 try isel.emit(.@"b."(
4500 .cmp_gte => switch (int_info.signedness) {4490 .vc,
4501 .signed => .ge,4491 @intCast((isel.instructions.items.len + 1 - cmp_info.cset_label) << 2),
4502 .unsigned => .hs,4492 ));
4503 },4493 var lhs_has_value_part_it = lhs_vi.field(ty, payload_size, 1);
4504 .cmp_gt => switch (int_info.bits) {4494 const lhs_has_value_part_vi = try lhs_has_value_part_it.only(isel);
4505 else => unreachable,4495 const lhs_has_value_part_mat = try lhs_has_value_part_vi.?.matReg(isel);
4506 1...64 => switch (int_info.signedness) {4496 var rhs_has_value_part_it = rhs_vi.field(ty, payload_size, 1);
4507 .signed => .gt,4497 const rhs_has_value_part_vi = try rhs_has_value_part_it.only(isel);
4508 .unsigned => .hi,4498 const rhs_has_value_part_mat = try rhs_has_value_part_vi.?.matReg(isel);
4509 },4499 try isel.emit(.ccmp(
4510 65...128 => {4500 lhs_has_value_part_mat.ra.w(),
4511 std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs);4501 .{ .register = rhs_has_value_part_mat.ra.w() },
4512 continue :cond .cmp_lt;4502 .{ .n = false, .z = false, .c = false, .v = true },
4513 },4503 .eq,
4504 ));
4505 try isel.emit(.ands(
4506 .wzr,
4507 lhs_has_value_part_mat.ra.w(),
4508 .{ .register = rhs_has_value_part_mat.ra.w() },
4509 ));
4510 try rhs_has_value_part_mat.finish(isel);
4511 try lhs_has_value_part_mat.finish(isel);
4512 break :unused;
4514 },4513 },
4515 .cmp_neq => .ne,
4516 })));
4517
4518 const lhs_vi = try isel.use(bin_op.lhs);
4519 const rhs_vi = try isel.use(bin_op.rhs);
4520 var part_offset = lhs_vi.size(isel);
4521 while (part_offset > 0) {
4522 const part_size = @min(part_offset, 8);
4523 part_offset -= part_size;
4524 var lhs_part_it = lhs_vi.field(ty, part_offset, part_size);
4525 const lhs_part_vi = try lhs_part_it.only(isel);
4526 const lhs_part_mat = try lhs_part_vi.?.matReg(isel);
4527 var rhs_part_it = rhs_vi.field(ty, part_offset, part_size);
4528 const rhs_part_vi = try rhs_part_it.only(isel);
4529 const rhs_part_mat = try rhs_part_vi.?.matReg(isel);
4530 try isel.emit(switch (part_size) {
4531 else => unreachable,
4532 1...4 => switch (part_offset) {
4533 0 => .subs(.wzr, lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }),
4534 else => switch (air_tag) {
4535 else => unreachable,
4536 .cmp_lt, .cmp_lte, .cmp_gte, .cmp_gt => .sbcs(
4537 .wzr,
4538 lhs_part_mat.ra.w(),
4539 rhs_part_mat.ra.w(),
4540 ),
4541 .cmp_eq, .cmp_neq => .ccmp(
4542 lhs_part_mat.ra.w(),
4543 .{ .register = rhs_part_mat.ra.w() },
4544 .{ .n = false, .z = false, .c = false, .v = false },
4545 .eq,
4546 ),
4547 },
4548 },
4549 5...8 => switch (part_offset) {
4550 0 => .subs(.xzr, lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }),
4551 else => switch (air_tag) {
4552 else => unreachable,
4553 .cmp_lt, .cmp_lte, .cmp_gte, .cmp_gt => .sbcs(
4554 .xzr,
4555 lhs_part_mat.ra.x(),
4556 rhs_part_mat.ra.x(),
4557 ),
4558 .cmp_eq, .cmp_neq => .ccmp(
4559 lhs_part_mat.ra.x(),
4560 .{ .register = rhs_part_mat.ra.x() },
4561 .{ .n = false, .z = false, .c = false, .v = false },
4562 .eq,
4563 ),
4564 },
4565 },
4566 });
4567 try rhs_part_mat.finish(isel);
4568 try lhs_part_mat.finish(isel);
4569 }
4570 } else switch (ty.floatBits(isel.target)) {
4571 else => unreachable,
4572 16, 32, 64 => |bits| {
4573 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4574 const need_fcvt = switch (bits) {
4575 else => unreachable,
4576 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
4577 32, 64 => false,
4578 };
4579 try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(switch (air_tag) {
4580 else => unreachable,
4581 .cmp_lt => .lo,
4582 .cmp_lte => .ls,
4583 .cmp_eq => .eq,
4584 .cmp_gte => .ge,
4585 .cmp_gt => .gt,
4586 .cmp_neq => .ne,
4587 })));
4588
4589 const lhs_vi = try isel.use(bin_op.lhs);
4590 const rhs_vi = try isel.use(bin_op.rhs);
4591 const lhs_mat = try lhs_vi.matReg(isel);
4592 const rhs_mat = try rhs_vi.matReg(isel);
4593 const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra;
4594 defer if (need_fcvt) isel.freeReg(lhs_ra);
4595 const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra;
4596 defer if (need_fcvt) isel.freeReg(rhs_ra);
4597 try isel.emit(bits: switch (bits) {
4598 else => unreachable,
4599 16 => if (need_fcvt)
4600 continue :bits 32
4601 else
4602 .fcmp(lhs_ra.h(), .{ .register = rhs_ra.h() }),
4603 32 => .fcmp(lhs_ra.s(), .{ .register = rhs_ra.s() }),
4604 64 => .fcmp(lhs_ra.d(), .{ .register = rhs_ra.d() }),
4605 });
4606 if (need_fcvt) {
4607 try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h()));
4608 try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h()));
4609 }
4610 try rhs_mat.finish(isel);
4611 try lhs_mat.finish(isel);
4612 },
4613 80, 128 => |bits| {
4614 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4615
4616 try call.prepareReturn(isel);
4617 try call.returnFill(isel, .r0);
4618 try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(cond: switch (air_tag) {
4619 else => unreachable,
4620 .cmp_lt => .lt,
4621 .cmp_lte => .le,
4622 .cmp_eq => .eq,
4623 .cmp_gte => {
4624 std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs);
4625 continue :cond .cmp_lte;
4626 },
4627 .cmp_gt => {
4628 std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs);
4629 continue :cond .cmp_lt;
4630 },
4631 .cmp_neq => .ne,
4632 })));
4633 try isel.emit(.subs(.wzr, .w0, .{ .immediate = 0 }));
4634 try call.finishReturn(isel);
4635
4636 try call.prepareCallee(isel);
4637 try isel.global_relocs.append(gpa, .{
4638 .name = switch (bits) {
4639 else => unreachable,
4640 16 => "__cmphf2",
4641 32 => "__cmpsf2",
4642 64 => "__cmpdf2",
4643 80 => "__cmpxf2",
4644 128 => "__cmptf2",
4645 },
4646 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
4647 });
4648 try isel.emit(.bl(0));
4649 try call.finishCallee(isel);
4650
4651 try call.prepareParams(isel);
4652 const lhs_vi = try isel.use(bin_op.lhs);
4653 const rhs_vi = try isel.use(bin_op.rhs);
4654 switch (bits) {
4655 else => unreachable,
4656 16, 32, 64, 128 => {
4657 try call.paramLiveOut(isel, rhs_vi, .v1);
4658 try call.paramLiveOut(isel, lhs_vi, .v0);
4659 },
4660 80 => {
4661 var rhs_hi16_it = rhs_vi.field(ty, 8, 8);
4662 const rhs_hi16_vi = try rhs_hi16_it.only(isel);
4663 try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3);
4664 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
4665 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
4666 try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2);
4667 var lhs_hi16_it = lhs_vi.field(ty, 8, 8);
4668 const lhs_hi16_vi = try lhs_hi16_it.only(isel);
4669 try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1);
4670 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
4671 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
4672 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
4673 },
4674 }
4675 try call.finishParams(isel);
4676 },4514 },
4677 }4515 }
4516 _ = try isel.cmp(
4517 try res_vi.value.defReg(isel) orelse break :unused,
4518 ty,
4519 try isel.use(bin_op.lhs),
4520 air_tag.toCmpOp().?,
4521 try isel.use(bin_op.rhs),
4522 );
4678 }4523 }
4679 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;4524 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4680 },4525 },
...@@ -5497,7 +5342,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -5497,7 +5342,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
5497 try src_mat.finish(isel);5342 try src_mat.finish(isel);
5498 },5343 },
5499 };5344 };
5500 } else return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });5345 } else return isel.fail("too big {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) });
5501 }5346 }
5502 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;5347 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5503 },5348 },
...@@ -5517,7 +5362,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -5517,7 +5362,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
5517 .int => .integer_out_of_bounds,5362 .int => .integer_out_of_bounds,
5518 .@"enum" => {5363 .@"enum" => {
5519 if (!dst_ty.isNonexhaustiveEnum(zcu)) {5364 if (!dst_ty.isNonexhaustiveEnum(zcu)) {
5520 return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });5365 return isel.fail("bad {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) });
5521 }5366 }
5522 break :panic_id .invalid_enum_value;5367 break :panic_id .invalid_enum_value;
5523 },5368 },
...@@ -5599,7 +5444,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -5599,7 +5444,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
5599 try src_mat.finish(isel);5444 try src_mat.finish(isel);
5600 }5445 }
5601 }5446 }
5602 } else return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });5447 } else return isel.fail("too big {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) });
5603 }5448 }
5604 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;5449 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5605 },5450 },
...@@ -5610,7 +5455,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -5610,7 +5455,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
5610 const ty_op = air.data(air.inst_index).ty_op;5455 const ty_op = air.data(air.inst_index).ty_op;
5611 const dst_ty = ty_op.ty.toType();5456 const dst_ty = ty_op.ty.toType();
5612 const src_ty = isel.air.typeOf(ty_op.operand, ip);5457 const src_ty = isel.air.typeOf(ty_op.operand, ip);
5613 if (!dst_ty.isAbiInt(zcu) or !src_ty.isAbiInt(zcu)) return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });5458 if (!dst_ty.isAbiInt(zcu) or !src_ty.isAbiInt(zcu)) return isel.fail("bad {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) });
5614 const dst_int_info = dst_ty.intInfo(zcu);5459 const dst_int_info = dst_ty.intInfo(zcu);
5615 switch (dst_int_info.bits) {5460 switch (dst_int_info.bits) {
5616 0 => unreachable,5461 0 => unreachable,
...@@ -5683,9 +5528,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -5683,9 +5528,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
5683 try src_lo64_vi.?.liveOut(isel, dst_lo64_ra);5528 try src_lo64_vi.?.liveOut(isel, dst_lo64_ra);
5684 }5529 }
5685 },5530 },
5686 else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }),5531 else => return isel.fail("too big {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) }),
5687 },5532 },
5688 else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }),5533 else => return isel.fail("too big {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) }),
5689 }5534 }
5690 }5535 }
5691 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;5536 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
...@@ -6487,7 +6332,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -6487,7 +6332,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
6487 const ty_op = air.data(air.inst_index).ty_op;6332 const ty_op = air.data(air.inst_index).ty_op;
6488 const dst_ty = ty_op.ty.toType();6333 const dst_ty = ty_op.ty.toType();
6489 const src_ty = isel.air.typeOf(ty_op.operand, ip);6334 const src_ty = isel.air.typeOf(ty_op.operand, ip);
6490 if (!dst_ty.isAbiInt(zcu)) return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });6335 if (!dst_ty.isAbiInt(zcu)) return isel.fail("bad {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) });
6491 const dst_int_info = dst_ty.intInfo(zcu);6336 const dst_int_info = dst_ty.intInfo(zcu);
6492 const src_bits = src_ty.floatBits(isel.target);6337 const src_bits = src_ty.floatBits(isel.target);
6493 switch (@max(dst_int_info.bits, src_bits)) {6338 switch (@max(dst_int_info.bits, src_bits)) {
...@@ -6617,7 +6462,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -6617,7 +6462,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
6617 }6462 }
6618 try call.finishParams(isel);6463 try call.finishParams(isel);
6619 },6464 },
6620 else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }),6465 else => return isel.fail("too big {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) }),
6621 }6466 }
6622 }6467 }
6623 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;6468 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
...@@ -6630,7 +6475,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -6630,7 +6475,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
6630 const dst_ty = ty_op.ty.toType();6475 const dst_ty = ty_op.ty.toType();
6631 const src_ty = isel.air.typeOf(ty_op.operand, ip);6476 const src_ty = isel.air.typeOf(ty_op.operand, ip);
6632 const dst_bits = dst_ty.floatBits(isel.target);6477 const dst_bits = dst_ty.floatBits(isel.target);
6633 if (!src_ty.isAbiInt(zcu)) return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });6478 if (!src_ty.isAbiInt(zcu)) return isel.fail("bad {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) });
6634 const src_int_info = src_ty.intInfo(zcu);6479 const src_int_info = src_ty.intInfo(zcu);
6635 switch (@max(dst_bits, src_int_info.bits)) {6480 switch (@max(dst_bits, src_int_info.bits)) {
6636 0 => unreachable,6481 0 => unreachable,
...@@ -6757,7 +6602,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -6757,7 +6602,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
6757 }6602 }
6758 try call.finishParams(isel);6603 try call.finishParams(isel);
6759 },6604 },
6760 else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }),6605 else => return isel.fail("too big {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) }),
6761 }6606 }
6762 }6607 }
6763 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;6608 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
...@@ -6836,7 +6681,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -6836,7 +6681,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
68366681
6837 break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag;6682 break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6838 },6683 },
6839 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty) }),6684 else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(dst_ty) }),
6840 }6685 }
6841 };6686 };
68426687
...@@ -7157,7 +7002,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -7157,7 +7002,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
7157 else => unreachable,7002 else => unreachable,
7158 },7003 },
7159 }),7004 }),
7160 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(union_ty) }),7005 else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(union_ty) }),
7161 }7006 }
7162 }7007 }
7163 var payload_it = union_vi.value.field(union_ty, union_layout.payloadOffset(), union_layout.payload_size);7008 var payload_it = union_vi.value.field(union_ty, union_layout.payloadOffset(), union_layout.payload_size);
...@@ -8499,6 +8344,217 @@ fn ctzLimb(...@@ -8499,6 +8344,217 @@ fn ctzLimb(
8499 }8344 }
8500}8345}
85018346
8347fn cmp(
8348 isel: *Select,
8349 res_ra: Register.Alias,
8350 ty: ZigType,
8351 orig_lhs_vi: Value.Index,
8352 op: std.math.CompareOperator,
8353 orig_rhs_vi: Value.Index,
8354) !struct { cset_label: usize } {
8355 var lhs_vi = orig_lhs_vi;
8356 var rhs_vi = orig_rhs_vi;
8357 if (!ty.isRuntimeFloat()) {
8358 const int_info: std.builtin.Type.Int = if (ty.toIntern() == .bool_type)
8359 .{ .signedness = .unsigned, .bits = 1 }
8360 else if (ty.isAbiInt(isel.pt.zcu))
8361 ty.intInfo(isel.pt.zcu)
8362 else if (ty.isPtrAtRuntime(isel.pt.zcu))
8363 .{ .signedness = .unsigned, .bits = 64 }
8364 else
8365 return isel.fail("bad cmp_{t} {f}", .{ op, isel.fmtType(ty) });
8366 if (int_info.bits > 256) return isel.fail("too big cmp_{t} {f}", .{ op, isel.fmtType(ty) });
8367 try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(cond: switch (op) {
8368 .lt => switch (int_info.signedness) {
8369 .signed => .lt,
8370 .unsigned => .lo,
8371 },
8372 .lte => switch (int_info.bits) {
8373 else => unreachable,
8374 1...64 => switch (int_info.signedness) {
8375 .signed => .le,
8376 .unsigned => .ls,
8377 },
8378 65...128 => {
8379 std.mem.swap(Value.Index, &lhs_vi, &rhs_vi);
8380 continue :cond .gte;
8381 },
8382 },
8383 .eq => .eq,
8384 .gte => switch (int_info.signedness) {
8385 .signed => .ge,
8386 .unsigned => .hs,
8387 },
8388 .gt => switch (int_info.bits) {
8389 else => unreachable,
8390 1...64 => switch (int_info.signedness) {
8391 .signed => .gt,
8392 .unsigned => .hi,
8393 },
8394 65...128 => {
8395 std.mem.swap(Value.Index, &lhs_vi, &rhs_vi);
8396 continue :cond .lt;
8397 },
8398 },
8399 .neq => .ne,
8400 })));
8401 const cset_label = isel.instructions.items.len;
8402
8403 var part_offset = lhs_vi.size(isel);
8404 while (part_offset > 0) {
8405 const part_size = @min(part_offset, 8);
8406 part_offset -= part_size;
8407 var lhs_part_it = lhs_vi.field(ty, part_offset, part_size);
8408 const lhs_part_vi = try lhs_part_it.only(isel);
8409 const lhs_part_mat = try lhs_part_vi.?.matReg(isel);
8410 var rhs_part_it = rhs_vi.field(ty, part_offset, part_size);
8411 const rhs_part_vi = try rhs_part_it.only(isel);
8412 const rhs_part_mat = try rhs_part_vi.?.matReg(isel);
8413 try isel.emit(switch (part_size) {
8414 else => unreachable,
8415 1...4 => switch (part_offset) {
8416 0 => .subs(.wzr, lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }),
8417 else => switch (op) {
8418 .lt, .lte, .gte, .gt => .sbcs(
8419 .wzr,
8420 lhs_part_mat.ra.w(),
8421 rhs_part_mat.ra.w(),
8422 ),
8423 .eq, .neq => .ccmp(
8424 lhs_part_mat.ra.w(),
8425 .{ .register = rhs_part_mat.ra.w() },
8426 .{ .n = false, .z = false, .c = false, .v = false },
8427 .eq,
8428 ),
8429 },
8430 },
8431 5...8 => switch (part_offset) {
8432 0 => .subs(.xzr, lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }),
8433 else => switch (op) {
8434 .lt, .lte, .gte, .gt => .sbcs(
8435 .xzr,
8436 lhs_part_mat.ra.x(),
8437 rhs_part_mat.ra.x(),
8438 ),
8439 .eq, .neq => .ccmp(
8440 lhs_part_mat.ra.x(),
8441 .{ .register = rhs_part_mat.ra.x() },
8442 .{ .n = false, .z = false, .c = false, .v = false },
8443 .eq,
8444 ),
8445 },
8446 },
8447 });
8448 try rhs_part_mat.finish(isel);
8449 try lhs_part_mat.finish(isel);
8450 }
8451 return .{ .cset_label = cset_label };
8452 }
8453 switch (ty.floatBits(isel.target)) {
8454 else => unreachable,
8455 16, 32, 64 => |bits| {
8456 const need_fcvt = switch (bits) {
8457 else => unreachable,
8458 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
8459 32, 64 => false,
8460 };
8461 try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(switch (op) {
8462 .lt => .lo,
8463 .lte => .ls,
8464 .eq => .eq,
8465 .gte => .ge,
8466 .gt => .gt,
8467 .neq => .ne,
8468 })));
8469 const cset_label = isel.instructions.items.len;
8470
8471 const lhs_mat = try lhs_vi.matReg(isel);
8472 const rhs_mat = try rhs_vi.matReg(isel);
8473 const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra;
8474 defer if (need_fcvt) isel.freeReg(lhs_ra);
8475 const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra;
8476 defer if (need_fcvt) isel.freeReg(rhs_ra);
8477 try isel.emit(bits: switch (bits) {
8478 else => unreachable,
8479 16 => if (need_fcvt)
8480 continue :bits 32
8481 else
8482 .fcmp(lhs_ra.h(), .{ .register = rhs_ra.h() }),
8483 32 => .fcmp(lhs_ra.s(), .{ .register = rhs_ra.s() }),
8484 64 => .fcmp(lhs_ra.d(), .{ .register = rhs_ra.d() }),
8485 });
8486 if (need_fcvt) {
8487 try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h()));
8488 try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h()));
8489 }
8490 try rhs_mat.finish(isel);
8491 try lhs_mat.finish(isel);
8492 return .{ .cset_label = cset_label };
8493 },
8494 80, 128 => |bits| {
8495 try call.prepareReturn(isel);
8496 try call.returnFill(isel, .r0);
8497 try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(cond: switch (op) {
8498 .lt => .lt,
8499 .lte => .le,
8500 .eq => .eq,
8501 .gte => {
8502 std.mem.swap(Value.Index, &lhs_vi, &rhs_vi);
8503 continue :cond .lte;
8504 },
8505 .gt => {
8506 std.mem.swap(Value.Index, &lhs_vi, &rhs_vi);
8507 continue :cond .lt;
8508 },
8509 .neq => .ne,
8510 })));
8511 const cset_label = isel.instructions.items.len;
8512 try isel.emit(.subs(.wzr, .w0, .{ .immediate = 0 }));
8513 try call.finishReturn(isel);
8514
8515 try call.prepareCallee(isel);
8516 try isel.global_relocs.append(isel.pt.zcu.gpa, .{
8517 .name = switch (bits) {
8518 else => unreachable,
8519 16 => "__cmphf2",
8520 32 => "__cmpsf2",
8521 64 => "__cmpdf2",
8522 80 => "__cmpxf2",
8523 128 => "__cmptf2",
8524 },
8525 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
8526 });
8527 try isel.emit(.bl(0));
8528 try call.finishCallee(isel);
8529
8530 try call.prepareParams(isel);
8531 switch (bits) {
8532 else => unreachable,
8533 16, 32, 64, 128 => {
8534 try call.paramLiveOut(isel, rhs_vi, .v1);
8535 try call.paramLiveOut(isel, lhs_vi, .v0);
8536 },
8537 80 => {
8538 var rhs_hi16_it = rhs_vi.field(ty, 8, 8);
8539 const rhs_hi16_vi = try rhs_hi16_it.only(isel);
8540 try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3);
8541 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
8542 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
8543 try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2);
8544 var lhs_hi16_it = lhs_vi.field(ty, 8, 8);
8545 const lhs_hi16_vi = try lhs_hi16_it.only(isel);
8546 try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1);
8547 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
8548 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
8549 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
8550 },
8551 }
8552 try call.finishParams(isel);
8553 return .{ .cset_label = cset_label };
8554 },
8555 }
8556}
8557
8502fn loadReg(8558fn loadReg(
8503 isel: *Select,8559 isel: *Select,
8504 ra: Register.Alias,8560 ra: Register.Alias,
...@@ -9272,9 +9328,9 @@ pub const Value = struct {...@@ -9272,9 +9328,9 @@ pub const Value = struct {
9272 opts: AddOrSubtractOptions,9328 opts: AddOrSubtractOptions,
9273 ) !void {9329 ) !void {
9274 const zcu = isel.pt.zcu;9330 const zcu = isel.pt.zcu;
9275 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(op), isel.fmtType(ty) });9331 if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ op, isel.fmtType(ty) });
9276 const int_info = ty.intInfo(zcu);9332 const int_info = ty.intInfo(zcu);
9277 if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(op), isel.fmtType(ty) });9333 if (int_info.bits > 128) return isel.fail("too big {t} {f}", .{ op, isel.fmtType(ty) });
9278 var part_offset = res_vi.size(isel);9334 var part_offset = res_vi.size(isel);
9279 var need_wrap = switch (opts.overflow) {9335 var need_wrap = switch (opts.overflow) {
9280 .@"unreachable" => false,9336 .@"unreachable" => false,
...@@ -10783,7 +10839,7 @@ pub const Value = struct {...@@ -10783,7 +10839,7 @@ pub const Value = struct {
10783 .err_name => continue :constant_key .{ .undef = error_union_type.payload_type },10839 .err_name => continue :constant_key .{ .undef = error_union_type.payload_type },
10784 .payload => |payload| {10840 .payload => |payload| {
10785 constant = payload;10841 constant = payload;
10786 constant_key = ip.indexToKey(payload);10842 constant_key = ip.indexToKey(constant);
10787 continue :constant_key constant_key;10843 continue :constant_key constant_key;
10788 },10844 },
10789 }10845 }
...@@ -11017,7 +11073,7 @@ pub const Value = struct {...@@ -11017,7 +11073,7 @@ pub const Value = struct {
11017 } } else .{ .undef = child_ty },11073 } } else .{ .undef = child_ty },
11018 else => |child| {11074 else => |child| {
11019 constant = child;11075 constant = child;
11020 constant_key = ip.indexToKey(child);11076 constant_key = ip.indexToKey(constant);
11021 continue :constant_key constant_key;11077 continue :constant_key constant_key;
11022 },11078 },
11023 };11079 };
...@@ -11040,7 +11096,7 @@ pub const Value = struct {...@@ -11040,7 +11096,7 @@ pub const Value = struct {
11040 },11096 },
11041 .repeated_elem => |repeated_elem| {11097 .repeated_elem => |repeated_elem| {
11042 constant = repeated_elem;11098 constant = repeated_elem;
11043 constant_key = ip.indexToKey(repeated_elem);11099 constant_key = ip.indexToKey(constant);
11044 continue :constant_key constant_key;11100 continue :constant_key constant_key;
11045 },11101 },
11046 };11102 };
...@@ -11099,6 +11155,28 @@ pub const Value = struct {...@@ -11099,6 +11155,28 @@ pub const Value = struct {
11099 }11155 }
11100 },11156 },
11101 },11157 },
11158 .un => |un| {
11159 const loaded_union = ip.loadUnionType(un.ty);
11160 const union_layout = ZigType.getUnionLayout(loaded_union, zcu);
11161 if (loaded_union.hasTag(ip)) {
11162 const tag_offset = union_layout.tagOffset();
11163 if (offset >= tag_offset and offset + size <= tag_offset + union_layout.tag_size) {
11164 offset -= tag_offset;
11165 continue :constant_key switch (ip.indexToKey(un.tag)) {
11166 else => unreachable,
11167 .int => |int| .{ .int = int },
11168 .enum_tag => |enum_tag| .{ .enum_tag = enum_tag },
11169 };
11170 }
11171 }
11172 const payload_offset = union_layout.payloadOffset();
11173 if (offset >= payload_offset and offset + size <= payload_offset + union_layout.payload_size) {
11174 offset -= payload_offset;
11175 constant = un.val;
11176 constant_key = ip.indexToKey(constant);
11177 continue :constant_key constant_key;
11178 }
11179 },
11102 else => {},11180 else => {},
11103 }11181 }
11104 var buffer: [16]u8 = @splat(0);11182 var buffer: [16]u8 = @splat(0);
...@@ -11259,7 +11337,7 @@ pub fn dumpValues(isel: *Select, which: enum { only_referenced, all }) void {...@@ -11259,7 +11337,7 @@ pub fn dumpValues(isel: *Select, which: enum { only_referenced, all }) void {
11259 first = false;11337 first = false;
11260 };11338 };
11261 if (reverse_live_registers.get(vi)) |ra| {11339 if (reverse_live_registers.get(vi)) |ra| {
11262 try stderr.print("{s}{s}", .{ if (first) " <- " else ", ", @tagName(ra) });11340 try stderr.print("{s}{t}", .{ if (first) " <- " else ", ", ra });
11263 first = false;11341 first = false;
11264 }11342 }
11265 }11343 }
...@@ -11267,8 +11345,8 @@ pub fn dumpValues(isel: *Select, which: enum { only_referenced, all }) void {...@@ -11267,8 +11345,8 @@ pub fn dumpValues(isel: *Select, which: enum { only_referenced, all }) void {
11267 switch (value.flags.parent_tag) {11345 switch (value.flags.parent_tag) {
11268 .unallocated => if (value.offset_from_parent != 0) try stderr.print(" +0x{x}", .{value.offset_from_parent}),11346 .unallocated => if (value.offset_from_parent != 0) try stderr.print(" +0x{x}", .{value.offset_from_parent}),
11269 .stack_slot => {11347 .stack_slot => {
11270 try stderr.print(" [{s}, #{s}0x{x}", .{11348 try stderr.print(" [{t}, #{s}0x{x}", .{
11271 @tagName(value.parent_payload.stack_slot.base),11349 value.parent_payload.stack_slot.base,
11272 if (value.parent_payload.stack_slot.offset < 0) "-" else "",11350 if (value.parent_payload.stack_slot.offset < 0) "-" else "",
11273 @abs(value.parent_payload.stack_slot.offset),11351 @abs(value.parent_payload.stack_slot.offset),
11274 });11352 });
...@@ -11282,7 +11360,7 @@ pub fn dumpValues(isel: *Select, which: enum { only_referenced, all }) void {...@@ -11282,7 +11360,7 @@ pub fn dumpValues(isel: *Select, which: enum { only_referenced, all }) void {
11282 isel.fmtConstant(value.parent_payload.constant),11360 isel.fmtConstant(value.parent_payload.constant),
11283 }),11361 }),
11284 }11362 }
11285 try stderr.print(" align({s})", .{@tagName(value.flags.alignment)});11363 try stderr.print(" align({t})", .{value.flags.alignment});
11286 switch (value.flags.location_tag) {11364 switch (value.flags.location_tag) {
11287 .large => try stderr.print(" size=0x{x} large", .{value.location_payload.large.size}),11365 .large => try stderr.print(" size=0x{x} large", .{value.location_payload.large.size}),
11288 .small => {11366 .small => {
...@@ -11292,8 +11370,8 @@ pub fn dumpValues(isel: *Select, which: enum { only_referenced, all }) void {...@@ -11292,8 +11370,8 @@ pub fn dumpValues(isel: *Select, which: enum { only_referenced, all }) void {
11292 .unsigned => {},11370 .unsigned => {},
11293 .signed => try stderr.writeAll(" signed"),11371 .signed => try stderr.writeAll(" signed"),
11294 }11372 }
11295 if (loc.hint != .zr) try stderr.print(" hint={s}", .{@tagName(loc.hint)});11373 if (loc.hint != .zr) try stderr.print(" hint={t}", .{loc.hint});
11296 if (loc.register != .zr) try stderr.print(" loc={s}", .{@tagName(loc.register)});11374 if (loc.register != .zr) try stderr.print(" loc={t}", .{loc.register});
11297 },11375 },
11298 }11376 }
11299 try stderr.print(" refs={d}\n", .{value.refs});11377 try stderr.print(" refs={d}\n", .{value.refs});
test/behavior/enum.zig-2
...@@ -899,7 +899,6 @@ test "enum value allocation" {...@@ -899,7 +899,6 @@ test "enum value allocation" {
899}899}
900900
901test "enum literal casting to tagged union" {901test "enum literal casting to tagged union" {
902 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
903 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;902 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
904 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO903 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
905904
...@@ -935,7 +934,6 @@ test "enum literal casting to error union with payload enum" {...@@ -935,7 +934,6 @@ test "enum literal casting to error union with payload enum" {
935}934}
936935
937test "constant enum initialization with differing sizes" {936test "constant enum initialization with differing sizes" {
938 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
939 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;937 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
940 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO938 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
941 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;939 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/optional.zig-2
...@@ -149,7 +149,6 @@ test "nested optional field in struct" {...@@ -149,7 +149,6 @@ test "nested optional field in struct" {
149}149}
150150
151test "equality compare optionals and non-optionals" {151test "equality compare optionals and non-optionals" {
152 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
153 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO152 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
154 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO153 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
155 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;154 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -209,7 +208,6 @@ test "equality compare optionals and non-optionals" {...@@ -209,7 +208,6 @@ test "equality compare optionals and non-optionals" {
209}208}
210209
211test "compare optionals with modified payloads" {210test "compare optionals with modified payloads" {
212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
213 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;211 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
214212
215 var lhs: ?bool = false;213 var lhs: ?bool = false;
test/behavior/switch.zig-2
...@@ -576,7 +576,6 @@ test "switch with null and T peer types and inferred result location type" {...@@ -576,7 +576,6 @@ test "switch with null and T peer types and inferred result location type" {
576}576}
577577
578test "switch prongs with cases with identical payload types" {578test "switch prongs with cases with identical payload types" {
579 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
580 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO579 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
581 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO580 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
582581
...@@ -824,7 +823,6 @@ test "comptime inline switch" {...@@ -824,7 +823,6 @@ test "comptime inline switch" {
824}823}
825824
826test "switch capture peer type resolution" {825test "switch capture peer type resolution" {
827 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
828 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;826 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
829827
830 const U = union(enum) {828 const U = union(enum) {
test/behavior/tuple.zig-1
...@@ -496,7 +496,6 @@ test "anon tuple field referencing comptime var isn't comptime" {...@@ -496,7 +496,6 @@ test "anon tuple field referencing comptime var isn't comptime" {
496}496}
497497
498test "tuple with runtime value coerced into a slice with a sentinel" {498test "tuple with runtime value coerced into a slice with a sentinel" {
499 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
500 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO499 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
501 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO500 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
502 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;501 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/union.zig-6
...@@ -208,7 +208,6 @@ const Payload = union(Letter) {...@@ -208,7 +208,6 @@ const Payload = union(Letter) {
208};208};
209209
210test "union with specified enum tag" {210test "union with specified enum tag" {
211 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
212 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;211 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
213 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO212 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
214 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;213 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -219,7 +218,6 @@ test "union with specified enum tag" {...@@ -219,7 +218,6 @@ test "union with specified enum tag" {
219}218}
220219
221test "packed union generates correctly aligned type" {220test "packed union generates correctly aligned type" {
222 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
223 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;221 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
224 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO222 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
225 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;223 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -605,7 +603,6 @@ fn returnAnInt(x: i32) TaggedFoo {...@@ -605,7 +603,6 @@ fn returnAnInt(x: i32) TaggedFoo {
605}603}
606604
607test "tagged union with all void fields but a meaningful tag" {605test "tagged union with all void fields but a meaningful tag" {
608 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
609 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;606 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
610 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO607 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
611608
...@@ -1032,7 +1029,6 @@ test "containers with single-field enums" {...@@ -1032,7 +1029,6 @@ test "containers with single-field enums" {
1032}1029}
10331030
1034test "@unionInit on union with tag but no fields" {1031test "@unionInit on union with tag but no fields" {
1035 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1036 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1032 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1037 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1033 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10381034
...@@ -1446,8 +1442,6 @@ test "access the tag of a global tagged union" {...@@ -1446,8 +1442,6 @@ test "access the tag of a global tagged union" {
1446}1442}
14471443
1448test "coerce enum literal to union in result loc" {1444test "coerce enum literal to union in result loc" {
1449 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1450
1451 const U = union(enum) {1445 const U = union(enum) {
1452 a,1446 a,
1453 b: u8,1447 b: u8,