authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-14 20:27:31-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-15 03:07:51-04:00
log77a8cb57287e8d6f8430f1dedecda2bfb30506f1
treeac760e910165c440ed8e5e96d349bab0d338405c
parent37ccf35ff207b8866b3fc433dd57d7c7d6bac710

x86_64: fix `@clz` and `@ctz` of `u8`


2 files changed, 52 insertions(+), 11 deletions(-)

src/arch/x86_64/CodeGen.zig+52-9
...@@ -4226,9 +4226,18 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {...@@ -4226,9 +4226,18 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
42264226
4227 const src_bits = src_ty.bitSize(self.target.*);4227 const src_bits = src_ty.bitSize(self.target.*);
4228 if (self.hasFeature(.lzcnt)) {4228 if (self.hasFeature(.lzcnt)) {
4229 if (src_bits <= 64) {4229 if (src_bits <= 8) {
4230 const wide_reg = try self.copyToTmpRegister(src_ty, mat_src_mcv);
4231 try self.truncateRegister(src_ty, wide_reg);
4232 try self.genBinOpMir(.{ ._, .lzcnt }, Type.u32, dst_mcv, .{ .register = wide_reg });
4233 try self.genBinOpMir(
4234 .{ ._, .sub },
4235 dst_ty,
4236 dst_mcv,
4237 .{ .immediate = 8 + self.regExtraBits(src_ty) },
4238 );
4239 } else if (src_bits <= 64) {
4230 try self.genBinOpMir(.{ ._, .lzcnt }, src_ty, dst_mcv, mat_src_mcv);4240 try self.genBinOpMir(.{ ._, .lzcnt }, src_ty, dst_mcv, mat_src_mcv);
4231
4232 const extra_bits = self.regExtraBits(src_ty);4241 const extra_bits = self.regExtraBits(src_ty);
4233 if (extra_bits > 0) {4242 if (extra_bits > 0) {
4234 try self.genBinOpMir(.{ ._, .sub }, dst_ty, dst_mcv, .{ .immediate = extra_bits });4243 try self.genBinOpMir(.{ ._, .sub }, dst_ty, dst_mcv, .{ .immediate = extra_bits });
...@@ -4267,7 +4276,17 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {...@@ -4267,7 +4276,17 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
4267 const imm_reg = try self.copyToTmpRegister(dst_ty, .{4276 const imm_reg = try self.copyToTmpRegister(dst_ty, .{
4268 .immediate = src_bits ^ (src_bits - 1),4277 .immediate = src_bits ^ (src_bits - 1),
4269 });4278 });
4270 try self.genBinOpMir(.{ ._, .bsr }, src_ty, dst_mcv, mat_src_mcv);4279 const imm_lock = self.register_manager.lockRegAssumeUnused(imm_reg);
4280 defer self.register_manager.unlockReg(imm_lock);
4281
4282 if (src_bits <= 8) {
4283 const wide_reg = try self.copyToTmpRegister(src_ty, mat_src_mcv);
4284 const wide_lock = self.register_manager.lockRegAssumeUnused(wide_reg);
4285 defer self.register_manager.unlockReg(wide_lock);
4286
4287 try self.truncateRegister(src_ty, wide_reg);
4288 try self.genBinOpMir(.{ ._, .bsr }, Type.u16, dst_mcv, .{ .register = wide_reg });
4289 } else try self.genBinOpMir(.{ ._, .bsr }, src_ty, dst_mcv, mat_src_mcv);
42714290
4272 const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);4291 const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);
4273 try self.asmCmovccRegisterRegister(4292 try self.asmCmovccRegisterRegister(
...@@ -4281,7 +4300,20 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {...@@ -4281,7 +4300,20 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
4281 const imm_reg = try self.copyToTmpRegister(dst_ty, .{4300 const imm_reg = try self.copyToTmpRegister(dst_ty, .{
4282 .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - self.regBitSize(dst_ty)),4301 .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - self.regBitSize(dst_ty)),
4283 });4302 });
4284 try self.genBinOpMir(.{ ._, .bsr }, src_ty, dst_mcv, mat_src_mcv);4303 const imm_lock = self.register_manager.lockRegAssumeUnused(imm_reg);
4304 defer self.register_manager.unlockReg(imm_lock);
4305
4306 const wide_reg = try self.copyToTmpRegister(src_ty, mat_src_mcv);
4307 const wide_lock = self.register_manager.lockRegAssumeUnused(wide_reg);
4308 defer self.register_manager.unlockReg(wide_lock);
4309
4310 try self.truncateRegister(src_ty, wide_reg);
4311 try self.genBinOpMir(
4312 .{ ._, .bsr },
4313 if (src_bits <= 8) Type.u16 else src_ty,
4314 dst_mcv,
4315 .{ .register = wide_reg },
4316 );
42854317
4286 const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);4318 const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);
4287 try self.asmCmovccRegisterRegister(4319 try self.asmCmovccRegisterRegister(
...@@ -4323,24 +4355,25 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {...@@ -4323,24 +4355,25 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
43234355
4324 if (self.hasFeature(.bmi)) {4356 if (self.hasFeature(.bmi)) {
4325 if (src_bits <= 64) {4357 if (src_bits <= 64) {
4326 const extra_bits = self.regExtraBits(src_ty);4358 const extra_bits = self.regExtraBits(src_ty) + @as(u64, if (src_bits <= 8) 8 else 0);
4359 const wide_ty = if (src_bits <= 8) Type.u16 else src_ty;
4327 const masked_mcv = if (extra_bits > 0) masked: {4360 const masked_mcv = if (extra_bits > 0) masked: {
4328 const tmp_mcv = tmp: {4361 const tmp_mcv = tmp: {
4329 if (src_mcv.isImmediate() or self.liveness.operandDies(inst, 0))4362 if (src_mcv.isImmediate() or self.liveness.operandDies(inst, 0))
4330 break :tmp src_mcv;4363 break :tmp src_mcv;
4331 try self.genSetReg(dst_reg, src_ty, src_mcv);4364 try self.genSetReg(dst_reg, wide_ty, src_mcv);
4332 break :tmp dst_mcv;4365 break :tmp dst_mcv;
4333 };4366 };
4334 try self.genBinOpMir(4367 try self.genBinOpMir(
4335 .{ ._, .@"or" },4368 .{ ._, .@"or" },
4336 src_ty,4369 wide_ty,
4337 tmp_mcv,4370 tmp_mcv,
4338 .{ .immediate = (@as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - extra_bits)) <<4371 .{ .immediate = (@as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - extra_bits)) <<
4339 @intCast(u6, src_bits) },4372 @intCast(u6, src_bits) },
4340 );4373 );
4341 break :masked tmp_mcv;4374 break :masked tmp_mcv;
4342 } else mat_src_mcv;4375 } else mat_src_mcv;
4343 try self.genBinOpMir(.{ ._, .tzcnt }, src_ty, dst_mcv, masked_mcv);4376 try self.genBinOpMir(.{ ._, .tzcnt }, wide_ty, dst_mcv, masked_mcv);
4344 } else if (src_bits <= 128) {4377 } else if (src_bits <= 128) {
4345 const tmp_reg = try self.register_manager.allocReg(null, gp);4378 const tmp_reg = try self.register_manager.allocReg(null, gp);
4346 const tmp_mcv = MCValue{ .register = tmp_reg };4379 const tmp_mcv = MCValue{ .register = tmp_reg };
...@@ -4369,7 +4402,17 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {...@@ -4369,7 +4402,17 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
4369 return self.fail("TODO airCtz of {}", .{src_ty.fmt(self.bin_file.options.module.?)});4402 return self.fail("TODO airCtz of {}", .{src_ty.fmt(self.bin_file.options.module.?)});
43704403
4371 const width_reg = try self.copyToTmpRegister(dst_ty, .{ .immediate = src_bits });4404 const width_reg = try self.copyToTmpRegister(dst_ty, .{ .immediate = src_bits });
4372 try self.genBinOpMir(.{ ._, .bsf }, src_ty, dst_mcv, mat_src_mcv);4405 const width_lock = self.register_manager.lockRegAssumeUnused(width_reg);
4406 defer self.register_manager.unlockReg(width_lock);
4407
4408 if (src_bits <= 8 or !math.isPowerOfTwo(src_bits)) {
4409 const wide_reg = try self.copyToTmpRegister(src_ty, mat_src_mcv);
4410 const wide_lock = self.register_manager.lockRegAssumeUnused(wide_reg);
4411 defer self.register_manager.unlockReg(wide_lock);
4412
4413 try self.truncateRegister(src_ty, wide_reg);
4414 try self.genBinOpMir(.{ ._, .bsf }, Type.u16, dst_mcv, .{ .register = wide_reg });
4415 } else try self.genBinOpMir(.{ ._, .bsf }, src_ty, dst_mcv, mat_src_mcv);
43734416
4374 const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);4417 const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);
4375 try self.asmCmovccRegisterRegister(4418 try self.asmCmovccRegisterRegister(
test/behavior/math.zig-2
...@@ -61,7 +61,6 @@ fn assertFalse(b: bool) !void {...@@ -61,7 +61,6 @@ fn assertFalse(b: bool) !void {
61}61}
6262
63test "@clz" {63test "@clz" {
64 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
65 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO64 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
66 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO65 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
67 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO66 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -142,7 +141,6 @@ fn expectVectorsEqual(a: anytype, b: anytype) !void {...@@ -142,7 +141,6 @@ fn expectVectorsEqual(a: anytype, b: anytype) !void {
142}141}
143142
144test "@ctz" {143test "@ctz" {
145 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
146 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
147 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO145 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
148 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO146 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO