authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-16 00:55:46-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-18 20:42:38-04:00
log36ddab03fa5b29248a7e8fe1770414dd0a4cc833
tree90f3bf19ee58480f201c2cdaa7518d2e8fbc888a
parent80df8da82f793c87217ec673ff980751461f8164

x86_64: fix multi-limb compare


2 files changed, 96 insertions(+), 16 deletions(-)

src/arch/x86_64/CodeGen.zig+96-15
...@@ -8171,24 +8171,105 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -8171,24 +8171,105 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
8171 const result = MCValue{8171 const result = MCValue{
8172 .eflags = switch (ty.zigTypeTag()) {8172 .eflags = switch (ty.zigTypeTag()) {
8173 else => result: {8173 else => result: {
8174 var flipped = false;8174 const abi_size = @intCast(u16, ty.abiSize(self.target.*));
8175 const dst_mcv: MCValue = if (lhs_mcv.isRegister() or lhs_mcv.isMemory())8175 const may_flip: enum {
8176 lhs_mcv8176 may_flip,
8177 else if (rhs_mcv.isRegister() or rhs_mcv.isMemory()) dst: {8177 must_flip,
8178 flipped = true;8178 must_not_flip,
8179 break :dst rhs_mcv;8179 } = if (abi_size > 8) switch (op) {
8180 } else .{ .register = try self.copyToTmpRegister(ty, lhs_mcv) };8180 .lt, .gte => .must_not_flip,
8181 const dst_lock = switch (dst_mcv) {8181 .lte, .gt => .must_flip,
8182 .register => |reg| self.register_manager.lockReg(reg),8182 .eq, .neq => .may_flip,
8183 else => null,8183 } else .may_flip;
8184
8185 const flipped = switch (may_flip) {
8186 .may_flip => !lhs_mcv.isRegister() and !lhs_mcv.isMemory(),
8187 .must_flip => true,
8188 .must_not_flip => false,
8189 };
8190 const unmat_dst_mcv = if (flipped) rhs_mcv else lhs_mcv;
8191 const dst_mcv = if (unmat_dst_mcv.isRegister() or
8192 (abi_size <= 8 and unmat_dst_mcv.isMemory())) unmat_dst_mcv else dst: {
8193 const dst_mcv = try self.allocTempRegOrMem(ty, true);
8194 try self.genCopy(ty, dst_mcv, unmat_dst_mcv);
8195 break :dst dst_mcv;
8184 };8196 };
8197 const dst_lock =
8198 if (dst_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
8185 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);8199 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
8200
8186 const src_mcv = if (flipped) lhs_mcv else rhs_mcv;8201 const src_mcv = if (flipped) lhs_mcv else rhs_mcv;
8202 const src_lock =
8203 if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
8204 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
81878205
8188 try self.genBinOpMir(.{ ._, .cmp }, ty, dst_mcv, src_mcv);
8189 break :result Condition.fromCompareOperator(8206 break :result Condition.fromCompareOperator(
8190 if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned,8207 if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned,
8191 if (flipped) op.reverse() else op,8208 result_op: {
8209 const flipped_op = if (flipped) op.reverse() else op;
8210 if (abi_size > 8) switch (flipped_op) {
8211 .lt, .gte => {},
8212 .lte, .gt => unreachable,
8213 .eq, .neq => {
8214 const dst_addr_mcv: MCValue = switch (dst_mcv) {
8215 .memory, .indirect, .load_frame => dst_mcv.address(),
8216 else => .{ .register = try self.copyToTmpRegister(
8217 Type.usize,
8218 dst_mcv.address(),
8219 ) },
8220 };
8221 const dst_addr_lock = if (dst_addr_mcv.getReg()) |reg|
8222 self.register_manager.lockReg(reg)
8223 else
8224 null;
8225 defer if (dst_addr_lock) |lock| self.register_manager.unlockReg(lock);
8226
8227 const src_addr_mcv: MCValue = switch (src_mcv) {
8228 .memory, .indirect, .load_frame => src_mcv.address(),
8229 else => .{ .register = try self.copyToTmpRegister(
8230 Type.usize,
8231 src_mcv.address(),
8232 ) },
8233 };
8234 const src_addr_lock = if (src_addr_mcv.getReg()) |reg|
8235 self.register_manager.lockReg(reg)
8236 else
8237 null;
8238 defer if (src_addr_lock) |lock| self.register_manager.unlockReg(lock);
8239
8240 const regs = try self.register_manager.allocRegs(2, .{ null, null }, gp);
8241 const acc_reg = regs[0].to64();
8242 const locks = self.register_manager.lockRegsAssumeUnused(2, regs);
8243 defer for (locks) |lock| self.register_manager.unlockReg(lock);
8244
8245 const limbs_len = std.math.divCeil(u16, abi_size, 8) catch unreachable;
8246 var limb_i: u16 = 0;
8247 while (limb_i < limbs_len) : (limb_i += 1) {
8248 const tmp_reg = regs[@min(limb_i, 1)].to64();
8249 try self.genSetReg(
8250 tmp_reg,
8251 Type.usize,
8252 dst_addr_mcv.offset(limb_i * 8).deref(),
8253 );
8254 try self.genBinOpMir(
8255 .{ ._, .xor },
8256 Type.usize,
8257 .{ .register = tmp_reg },
8258 src_addr_mcv.offset(limb_i * 8).deref(),
8259 );
8260 if (limb_i > 0) try self.asmRegisterRegister(
8261 .{ ._, .@"or" },
8262 acc_reg,
8263 tmp_reg,
8264 );
8265 }
8266 try self.asmRegisterRegister(.{ ._, .@"test" }, acc_reg, acc_reg);
8267 break :result_op flipped_op;
8268 },
8269 };
8270 try self.genBinOpMir(.{ ._, .cmp }, ty, dst_mcv, src_mcv);
8271 break :result_op flipped_op;
8272 },
8192 );8273 );
8193 },8274 },
8194 .Float => result: {8275 .Float => result: {
...@@ -10006,7 +10087,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -10006,7 +10087,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
10006 if (src_ty.isAbiInt()) src_ty.intInfo(self.target.*).signedness else .unsigned;10087 if (src_ty.isAbiInt()) src_ty.intInfo(self.target.*).signedness else .unsigned;
10007 const abi_size = @intCast(u16, dst_ty.abiSize(self.target.*));10088 const abi_size = @intCast(u16, dst_ty.abiSize(self.target.*));
10008 const bit_size = @intCast(u16, dst_ty.bitSize(self.target.*));10089 const bit_size = @intCast(u16, dst_ty.bitSize(self.target.*));
10009 const dst_limbs_len = std.math.divCeil(u16, bit_size, 64) catch unreachable;10090 const dst_limbs_len = math.divCeil(u16, bit_size, 64) catch unreachable;
10010 if (dst_signedness != src_signedness and abi_size * 8 > bit_size) {10091 if (dst_signedness != src_signedness and abi_size * 8 > bit_size) {
10011 const high_reg = if (dst_mcv.isRegister())10092 const high_reg = if (dst_mcv.isRegister())
10012 dst_mcv.getReg().?10093 dst_mcv.getReg().?
...@@ -10071,7 +10152,7 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void {...@@ -10071,7 +10152,7 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void {
10071 if (src_ty.isAbiInt()) src_ty.intInfo(self.target.*).signedness else .unsigned;10152 if (src_ty.isAbiInt()) src_ty.intInfo(self.target.*).signedness else .unsigned;
10072 const dst_ty = self.air.typeOfIndex(inst);10153 const dst_ty = self.air.typeOfIndex(inst);
1007310154
10074 const src_size = std.math.divCeil(u32, @max(switch (src_signedness) {10155 const src_size = math.divCeil(u32, @max(switch (src_signedness) {
10075 .signed => src_bits,10156 .signed => src_bits,
10076 .unsigned => src_bits + 1,10157 .unsigned => src_bits + 1,
10077 }, 32), 8) catch unreachable;10158 }, 32), 8) catch unreachable;
...@@ -10124,7 +10205,7 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {...@@ -10124,7 +10205,7 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {
10124 const dst_signedness =10205 const dst_signedness =
10125 if (dst_ty.isAbiInt()) dst_ty.intInfo(self.target.*).signedness else .unsigned;10206 if (dst_ty.isAbiInt()) dst_ty.intInfo(self.target.*).signedness else .unsigned;
1012610207
10127 const dst_size = std.math.divCeil(u32, @max(switch (dst_signedness) {10208 const dst_size = math.divCeil(u32, @max(switch (dst_signedness) {
10128 .signed => dst_bits,10209 .signed => dst_bits,
10129 .unsigned => dst_bits + 1,10210 .unsigned => dst_bits + 1,
10130 }, 32), 8) catch unreachable;10211 }, 32), 8) catch unreachable;
test/behavior/floatop.zig-1
...@@ -1145,7 +1145,6 @@ test "nan negation f64" {...@@ -1145,7 +1145,6 @@ test "nan negation f64" {
11451145
1146test "nan negation f128" {1146test "nan negation f128" {
1147 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1147 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1148 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1149 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1150 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1149 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1151 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1150 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO