aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJacob Young <jacobly0@users.noreply.github.com>2023-04-13 04:06:17 -0400
committerJacob Young <jacobly0@users.noreply.github.com>2023-04-13 04:17:54 -0400
commite72c41a32af41c15f4f73b46c902c01ed838462f (patch)
tree6613ba68b7236f1fa3d3def5b854ffeba2677694 /src
parentcaa3d6a4f4413c1cace517b073476780168f24cf (diff)
downloadzig-e72c41a32af41c15f4f73b46c902c01ed838462f.tar.gz
zig-e72c41a32af41c15f4f73b46c902c01ed838462f.zip
x86_64: fix clz miscompile
Diffstat (limited to 'src')
-rw-r--r--src/arch/x86_64/CodeGen.zig42
1 files changed, 30 insertions, 12 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 63ba74da1c..7344af9673 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -3083,7 +3083,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
};
defer if (mat_src_lock) |lock| self.register_manager.unlockReg(lock);
- const dst_reg = try self.register_manager.allocReg(null, gp);
+ const dst_reg = try self.register_manager.allocReg(inst, gp);
const dst_mcv = MCValue{ .register = dst_reg };
const dst_lock = self.register_manager.lockReg(dst_reg);
defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
@@ -3098,19 +3098,37 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
}
const src_bits = src_ty.bitSize(self.target.*);
- const width_mcv =
- try self.copyToRegisterWithInstTracking(inst, dst_ty, .{ .immediate = src_bits });
- try self.genBinOpMir(.bsr, src_ty, dst_mcv, mat_src_mcv);
+ if (math.isPowerOfTwo(src_bits)) {
+ const imm_reg = try self.copyToTmpRegister(dst_ty, .{
+ .immediate = src_bits ^ (src_bits - 1),
+ });
+ try self.genBinOpMir(.bsf, src_ty, dst_mcv, mat_src_mcv);
- const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);
- try self.asmCmovccRegisterRegister(
- registerAlias(dst_reg, cmov_abi_size),
- registerAlias(width_mcv.register, cmov_abi_size),
- .z,
- );
+ const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);
+ try self.asmCmovccRegisterRegister(
+ registerAlias(dst_reg, cmov_abi_size),
+ registerAlias(imm_reg, cmov_abi_size),
+ .z,
+ );
- try self.genBinOpMir(.sub, dst_ty, width_mcv, dst_mcv);
- break :result width_mcv;
+ try self.genBinOpMir(.xor, dst_ty, dst_mcv, .{ .immediate = src_bits - 1 });
+ } else {
+ const imm_reg = try self.copyToTmpRegister(dst_ty, .{
+ .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - self.regBitSize(dst_ty)),
+ });
+ try self.genBinOpMir(.bsf, src_ty, dst_mcv, mat_src_mcv);
+
+ const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);
+ try self.asmCmovccRegisterRegister(
+ registerAlias(imm_reg, cmov_abi_size),
+ registerAlias(dst_reg, cmov_abi_size),
+ .nz,
+ );
+
+ try self.genSetReg(dst_ty, dst_reg, .{ .immediate = src_bits - 1 });
+ try self.genBinOpMir(.sub, dst_ty, dst_mcv, .{ .register = imm_reg });
+ }
+ break :result dst_mcv;
};
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}