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 {
42264226
42274227 const src_bits = src_ty.bitSize(self.target.*);
42284228 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) {
42304240 try self.genBinOpMir(.{ ._, .lzcnt }, src_ty, dst_mcv, mat_src_mcv);
4231
42324241 const extra_bits = self.regExtraBits(src_ty);
42334242 if (extra_bits > 0) {
42344243 try self.genBinOpMir(.{ ._, .sub }, dst_ty, dst_mcv, .{ .immediate = extra_bits });
......@@ -4267,7 +4276,17 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
42674276 const imm_reg = try self.copyToTmpRegister(dst_ty, .{
42684277 .immediate = src_bits ^ (src_bits - 1),
42694278 });
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
42724291 const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);
42734292 try self.asmCmovccRegisterRegister(
......@@ -4281,7 +4300,20 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
42814300 const imm_reg = try self.copyToTmpRegister(dst_ty, .{
42824301 .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - self.regBitSize(dst_ty)),
42834302 });
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
42864318 const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);
42874319 try self.asmCmovccRegisterRegister(
......@@ -4323,24 +4355,25 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
43234355
43244356 if (self.hasFeature(.bmi)) {
43254357 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;
43274360 const masked_mcv = if (extra_bits > 0) masked: {
43284361 const tmp_mcv = tmp: {
43294362 if (src_mcv.isImmediate() or self.liveness.operandDies(inst, 0))
43304363 break :tmp src_mcv;
4331 try self.genSetReg(dst_reg, src_ty, src_mcv);
4364 try self.genSetReg(dst_reg, wide_ty, src_mcv);
43324365 break :tmp dst_mcv;
43334366 };
43344367 try self.genBinOpMir(
43354368 .{ ._, .@"or" },
4336 src_ty,
4369 wide_ty,
43374370 tmp_mcv,
43384371 .{ .immediate = (@as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - extra_bits)) <<
43394372 @intCast(u6, src_bits) },
43404373 );
43414374 break :masked tmp_mcv;
43424375 } 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);
43444377 } else if (src_bits <= 128) {
43454378 const tmp_reg = try self.register_manager.allocReg(null, gp);
43464379 const tmp_mcv = MCValue{ .register = tmp_reg };
......@@ -4369,7 +4402,17 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
43694402 return self.fail("TODO airCtz of {}", .{src_ty.fmt(self.bin_file.options.module.?)});
43704403
43714404 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
43744417 const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);
43754418 try self.asmCmovccRegisterRegister(
test/behavior/math.zig-2
......@@ -61,7 +61,6 @@ fn assertFalse(b: bool) !void {
6161}
6262
6363test "@clz" {
64 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
6564 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6665 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6766 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -142,7 +141,6 @@ fn expectVectorsEqual(a: anytype, b: anytype) !void {
142141}
143142
144143test "@ctz" {
145 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
146144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
147145 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
148146 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO