aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-10-29 17:48:34 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-10-29 17:49:02 -0700
commitd6067db06267e37dec65202667741bc1b63fe980 (patch)
treea693698a60b30a7d0ca2764056858c8b74066cd7 /src/codegen
parent5ff01bd820ea08005a422f046ad5bbad663b0dab (diff)
downloadzig-d6067db06267e37dec65202667741bc1b63fe980.tar.gz
zig-d6067db06267e37dec65202667741bc1b63fe980.zip
stage2: implement `@popCount` for non-vectors
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/c.zig1
-rw-r--r--src/codegen/llvm.zig35
2 files changed, 36 insertions, 0 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 3ab74a85be..8e046264aa 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -1107,6 +1107,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.get_union_tag => try airGetUnionTag(f, inst),
.clz => try airBuiltinCall(f, inst, "clz"),
.ctz => try airBuiltinCall(f, inst, "ctz"),
+ .popcount => try airBuiltinCall(f, inst, "popcount"),
.int_to_float,
.float_to_int,
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 572e23ff28..683ee9b95b 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -1777,6 +1777,7 @@ pub const FuncGen = struct {
.get_union_tag => try self.airGetUnionTag(inst),
.clz => try self.airClzCtz(inst, "ctlz"),
.ctz => try self.airClzCtz(inst, "cttz"),
+ .popcount => try self.airPopCount(inst, "ctpop"),
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
.atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
@@ -3679,6 +3680,40 @@ pub const FuncGen = struct {
}
}
+ fn airPopCount(self: *FuncGen, inst: Air.Inst.Index, prefix: [*:0]const u8) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst)) return null;
+
+ const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+ const operand_ty = self.air.typeOf(ty_op.operand);
+ const operand = try self.resolveInst(ty_op.operand);
+ const target = self.dg.module.getTarget();
+ const bits = operand_ty.intInfo(target).bits;
+
+ var fn_name_buf: [100]u8 = undefined;
+ const llvm_fn_name = std.fmt.bufPrintZ(&fn_name_buf, "llvm.{s}.i{d}", .{
+ prefix, bits,
+ }) catch unreachable;
+ const fn_val = self.dg.object.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {
+ const operand_llvm_ty = try self.dg.llvmType(operand_ty);
+ const param_types = [_]*const llvm.Type{operand_llvm_ty};
+ const fn_type = llvm.functionType(operand_llvm_ty, &param_types, param_types.len, .False);
+ break :blk self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type);
+ };
+
+ const params = [_]*const llvm.Value{operand};
+ const wrong_size_result = self.builder.buildCall(fn_val, &params, params.len, .C, .Auto, "");
+ const result_ty = self.air.typeOfIndex(inst);
+ const result_llvm_ty = try self.dg.llvmType(result_ty);
+ const result_bits = result_ty.intInfo(target).bits;
+ if (bits > result_bits) {
+ return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, "");
+ } else if (bits < result_bits) {
+ return self.builder.buildZExt(wrong_size_result, result_llvm_ty, "");
+ } else {
+ return wrong_size_result;
+ }
+ }
+
fn callFloor(self: *FuncGen, arg: *const llvm.Value, ty: Type) !*const llvm.Value {
return self.callFloatUnary(arg, ty, "floor");
}