Skip to content

Commit d8295c1

Browse files
committed
add @popcount intrinsic
1 parent e19f0b5 commit d8295c1

11 files changed

+205
-6
lines changed

doc/langref.html.in

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5013,7 +5013,7 @@ comptime {
50135013
<p>
50145014
If <code>x</code> is zero, <code>@clz</code> returns <code>T.bit_count</code>.
50155015
</p>
5016-
5016+
{#see_also|@ctz|@popCount#}
50175017
{#header_close#}
50185018
{#header_open|@cmpxchgStrong#}
50195019
<pre><code class="zig">@cmpxchgStrong(comptime T: type, ptr: *T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) ?T</code></pre>
@@ -5149,6 +5149,7 @@ test "main" {
51495149
<p>
51505150
If <code>x</code> is zero, <code>@ctz</code> returns <code>T.bit_count</code>.
51515151
</p>
5152+
{#see_also|@clz|@popCount#}
51525153
{#header_close#}
51535154
{#header_open|@divExact#}
51545155
<pre><code class="zig">@divExact(numerator: T, denominator: T) T</code></pre>
@@ -5631,6 +5632,16 @@ test "call foo" {
56315632
</ul>
56325633
{#see_also|Root Source File#}
56335634
{#header_close#}
5635+
{#header_open|@popCount#}
5636+
<pre><code class="zig">@popCount(integer: var) var</code></pre>
5637+
<p>Counts the number of bits set in an integer.</p>
5638+
<p>
5639+
If <code>integer</code> is known at {#link|comptime#}, the return type is <code>comptime_int</code>.
5640+
Otherwise, the return type is an unsigned integer with the minimum number
5641+
of bits that can represent the bit count of the integer type.
5642+
</p>
5643+
{#see_also|@ctz|@clz#}
5644+
{#header_close#}
56345645
{#header_open|@ptrCast#}
56355646
<pre><code class="zig">@ptrCast(comptime DestType: type, value: var) DestType</code></pre>
56365647
<p>
@@ -7337,7 +7348,7 @@ hljs.registerLanguage("zig", function(t) {
73377348
a = t.IR + "\\s*\\(",
73387349
c = {
73397350
keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong resume cancel await async orelse",
7340-
built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage divTrunc divFloor enumTagName intToPtr ptrToInt panic ptrCast intCast floatCast intToFloat floatToInt boolToInt bytesToSlice sliceToBytes errSetCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo typeName newStackCall errorToInt intToError enumToInt intToEnum",
7351+
built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage divTrunc divFloor enumTagName intToPtr ptrToInt panic ptrCast intCast floatCast intToFloat floatToInt boolToInt bytesToSlice sliceToBytes errSetCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz popCount import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo typeName newStackCall errorToInt intToError enumToInt intToEnum",
73417352
literal: "true false null undefined"
73427353
},
73437354
n = [e, t.CLCM, t.CBCM, s, r];

src/all_types.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,6 +1352,7 @@ enum BuiltinFnId {
13521352
BuiltinFnIdCompileLog,
13531353
BuiltinFnIdCtz,
13541354
BuiltinFnIdClz,
1355+
BuiltinFnIdPopCount,
13551356
BuiltinFnIdImport,
13561357
BuiltinFnIdCImport,
13571358
BuiltinFnIdErrName,
@@ -1477,6 +1478,7 @@ bool type_id_eql(TypeId a, TypeId b);
14771478
enum ZigLLVMFnId {
14781479
ZigLLVMFnIdCtz,
14791480
ZigLLVMFnIdClz,
1481+
ZigLLVMFnIdPopCount,
14801482
ZigLLVMFnIdOverflowArithmetic,
14811483
ZigLLVMFnIdFloor,
14821484
ZigLLVMFnIdCeil,
@@ -1499,6 +1501,9 @@ struct ZigLLVMFnKey {
14991501
struct {
15001502
uint32_t bit_count;
15011503
} clz;
1504+
struct {
1505+
uint32_t bit_count;
1506+
} pop_count;
15021507
struct {
15031508
uint32_t bit_count;
15041509
} floating;
@@ -2050,6 +2055,7 @@ enum IrInstructionId {
20502055
IrInstructionIdUnionTag,
20512056
IrInstructionIdClz,
20522057
IrInstructionIdCtz,
2058+
IrInstructionIdPopCount,
20532059
IrInstructionIdImport,
20542060
IrInstructionIdCImport,
20552061
IrInstructionIdCInclude,
@@ -2545,6 +2551,12 @@ struct IrInstructionClz {
25452551
IrInstruction *value;
25462552
};
25472553

2554+
struct IrInstructionPopCount {
2555+
IrInstruction base;
2556+
2557+
IrInstruction *value;
2558+
};
2559+
25482560
struct IrInstructionUnionTag {
25492561
IrInstruction base;
25502562

src/analyze.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5976,6 +5976,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) {
59765976
return (uint32_t)(x.data.ctz.bit_count) * (uint32_t)810453934;
59775977
case ZigLLVMFnIdClz:
59785978
return (uint32_t)(x.data.clz.bit_count) * (uint32_t)2428952817;
5979+
case ZigLLVMFnIdPopCount:
5980+
return (uint32_t)(x.data.clz.bit_count) * (uint32_t)101195049;
59795981
case ZigLLVMFnIdFloor:
59805982
return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1899859168;
59815983
case ZigLLVMFnIdCeil:
@@ -5998,6 +6000,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {
59986000
return a.data.ctz.bit_count == b.data.ctz.bit_count;
59996001
case ZigLLVMFnIdClz:
60006002
return a.data.clz.bit_count == b.data.clz.bit_count;
6003+
case ZigLLVMFnIdPopCount:
6004+
return a.data.pop_count.bit_count == b.data.pop_count.bit_count;
60016005
case ZigLLVMFnIdFloor:
60026006
case ZigLLVMFnIdCeil:
60036007
case ZigLLVMFnIdSqrt:

src/bigint.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1593,6 +1593,37 @@ void bigint_append_buf(Buf *buf, const BigInt *op, uint64_t base) {
15931593
}
15941594
}
15951595

1596+
size_t bigint_popcount_unsigned(const BigInt *bi) {
1597+
assert(!bi->is_negative);
1598+
if (bi->digit_count == 0)
1599+
return 0;
1600+
1601+
size_t count = 0;
1602+
size_t bit_count = bi->digit_count * 64;
1603+
for (size_t i = 0; i < bit_count; i += 1) {
1604+
if (bit_at_index(bi, i))
1605+
count += 1;
1606+
}
1607+
return count;
1608+
}
1609+
1610+
size_t bigint_popcount_signed(const BigInt *bi, size_t bit_count) {
1611+
if (bit_count == 0)
1612+
return 0;
1613+
if (bi->digit_count == 0)
1614+
return 0;
1615+
1616+
BigInt twos_comp = {0};
1617+
to_twos_complement(&twos_comp, bi, bit_count);
1618+
1619+
size_t count = 0;
1620+
for (size_t i = 0; i < bit_count; i += 1) {
1621+
if (bit_at_index(&twos_comp, i))
1622+
count += 1;
1623+
}
1624+
return count;
1625+
}
1626+
15961627
size_t bigint_ctz(const BigInt *bi, size_t bit_count) {
15971628
if (bit_count == 0)
15981629
return 0;

src/bigint.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ void bigint_append_buf(Buf *buf, const BigInt *op, uint64_t base);
8181

8282
size_t bigint_ctz(const BigInt *bi, size_t bit_count);
8383
size_t bigint_clz(const BigInt *bi, size_t bit_count);
84+
size_t bigint_popcount_signed(const BigInt *bi, size_t bit_count);
85+
size_t bigint_popcount_unsigned(const BigInt *bi);
8486

8587
size_t bigint_bits_needed(const BigInt *op);
8688

src/codegen.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3426,14 +3426,22 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
34263426
static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, BuiltinFnId fn_id) {
34273427
ZigLLVMFnKey key = {};
34283428
const char *fn_name;
3429+
uint32_t n_args;
34293430
if (fn_id == BuiltinFnIdCtz) {
34303431
fn_name = "cttz";
3432+
n_args = 2;
34313433
key.id = ZigLLVMFnIdCtz;
34323434
key.data.ctz.bit_count = (uint32_t)int_type->data.integral.bit_count;
34333435
} else if (fn_id == BuiltinFnIdClz) {
34343436
fn_name = "ctlz";
3437+
n_args = 2;
34353438
key.id = ZigLLVMFnIdClz;
34363439
key.data.clz.bit_count = (uint32_t)int_type->data.integral.bit_count;
3440+
} else if (fn_id == BuiltinFnIdPopCount) {
3441+
fn_name = "ctpop";
3442+
n_args = 1;
3443+
key.id = ZigLLVMFnIdPopCount;
3444+
key.data.pop_count.bit_count = (uint32_t)int_type->data.integral.bit_count;
34373445
} else {
34383446
zig_unreachable();
34393447
}
@@ -3448,7 +3456,7 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, Bui
34483456
int_type->type_ref,
34493457
LLVMInt1Type(),
34503458
};
3451-
LLVMTypeRef fn_type = LLVMFunctionType(int_type->type_ref, param_types, 2, false);
3459+
LLVMTypeRef fn_type = LLVMFunctionType(int_type->type_ref, param_types, n_args, false);
34523460
LLVMValueRef fn_val = LLVMAddFunction(g->module, llvm_name, fn_type);
34533461
assert(LLVMGetIntrinsicID(fn_val));
34543462

@@ -3481,6 +3489,14 @@ static LLVMValueRef ir_render_ctz(CodeGen *g, IrExecutable *executable, IrInstru
34813489
return gen_widen_or_shorten(g, false, int_type, instruction->base.value.type, wrong_size_int);
34823490
}
34833491

3492+
static LLVMValueRef ir_render_pop_count(CodeGen *g, IrExecutable *executable, IrInstructionPopCount *instruction) {
3493+
TypeTableEntry *int_type = instruction->value->value.type;
3494+
LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdPopCount);
3495+
LLVMValueRef operand = ir_llvm_value(g, instruction->value);
3496+
LLVMValueRef wrong_size_int = LLVMBuildCall(g->builder, fn_val, &operand, 1, "");
3497+
return gen_widen_or_shorten(g, false, int_type, instruction->base.value.type, wrong_size_int);
3498+
}
3499+
34843500
static LLVMValueRef ir_render_switch_br(CodeGen *g, IrExecutable *executable, IrInstructionSwitchBr *instruction) {
34853501
LLVMValueRef target_value = ir_llvm_value(g, instruction->target_value);
34863502
LLVMBasicBlockRef else_block = instruction->else_block->llvm_block;
@@ -4831,6 +4847,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
48314847
return ir_render_clz(g, executable, (IrInstructionClz *)instruction);
48324848
case IrInstructionIdCtz:
48334849
return ir_render_ctz(g, executable, (IrInstructionCtz *)instruction);
4850+
case IrInstructionIdPopCount:
4851+
return ir_render_pop_count(g, executable, (IrInstructionPopCount *)instruction);
48344852
case IrInstructionIdSwitchBr:
48354853
return ir_render_switch_br(g, executable, (IrInstructionSwitchBr *)instruction);
48364854
case IrInstructionIdPhi:
@@ -6342,6 +6360,7 @@ static void define_builtin_fns(CodeGen *g) {
63426360
create_builtin_fn(g, BuiltinFnIdCUndef, "cUndef", 1);
63436361
create_builtin_fn(g, BuiltinFnIdCtz, "ctz", 1);
63446362
create_builtin_fn(g, BuiltinFnIdClz, "clz", 1);
6363+
create_builtin_fn(g, BuiltinFnIdPopCount, "popCount", 1);
63456364
create_builtin_fn(g, BuiltinFnIdImport, "import", 1);
63466365
create_builtin_fn(g, BuiltinFnIdCImport, "cImport", 1);
63476366
create_builtin_fn(g, BuiltinFnIdErrName, "errorName", 1);

src/ir.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCtz *) {
427427
return IrInstructionIdCtz;
428428
}
429429

430+
static constexpr IrInstructionId ir_instruction_id(IrInstructionPopCount *) {
431+
return IrInstructionIdPopCount;
432+
}
433+
430434
static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionTag *) {
431435
return IrInstructionIdUnionTag;
432436
}
@@ -1725,6 +1729,15 @@ static IrInstruction *ir_build_ctz_from(IrBuilder *irb, IrInstruction *old_instr
17251729
return new_instruction;
17261730
}
17271731

1732+
static IrInstruction *ir_build_pop_count(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
1733+
IrInstructionPopCount *instruction = ir_build_instruction<IrInstructionPopCount>(irb, scope, source_node);
1734+
instruction->value = value;
1735+
1736+
ir_ref_instruction(value, irb->current_basic_block);
1737+
1738+
return &instruction->base;
1739+
}
1740+
17281741
static IrInstruction *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target_value,
17291742
IrBasicBlock *else_block, size_t case_count, IrInstructionSwitchBrCase *cases, IrInstruction *is_comptime,
17301743
IrInstruction *switch_prongs_void)
@@ -3841,6 +3854,16 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
38413854
IrInstruction *ctz = ir_build_ctz(irb, scope, node, arg0_value);
38423855
return ir_lval_wrap(irb, scope, ctz, lval);
38433856
}
3857+
case BuiltinFnIdPopCount:
3858+
{
3859+
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
3860+
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
3861+
if (arg0_value == irb->codegen->invalid_instruction)
3862+
return arg0_value;
3863+
3864+
IrInstruction *instr = ir_build_pop_count(irb, scope, node, arg0_value);
3865+
return ir_lval_wrap(irb, scope, instr, lval);
3866+
}
38443867
case BuiltinFnIdClz:
38453868
{
38463869
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
@@ -15275,6 +15298,48 @@ static TypeTableEntry *ir_analyze_instruction_clz(IrAnalyze *ira, IrInstructionC
1527515298
}
1527615299
}
1527715300

15301+
static TypeTableEntry *ir_analyze_instruction_pop_count(IrAnalyze *ira, IrInstructionPopCount *instruction) {
15302+
IrInstruction *value = instruction->value->other;
15303+
if (type_is_invalid(value->value.type))
15304+
return ira->codegen->builtin_types.entry_invalid;
15305+
15306+
if (value->value.type->id != TypeTableEntryIdInt && value->value.type->id != TypeTableEntryIdComptimeInt) {
15307+
ir_add_error(ira, value,
15308+
buf_sprintf("expected integer type, found '%s'", buf_ptr(&value->value.type->name)));
15309+
return ira->codegen->builtin_types.entry_invalid;
15310+
}
15311+
15312+
if (instr_is_comptime(value)) {
15313+
ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
15314+
if (!val)
15315+
return ira->codegen->builtin_types.entry_invalid;
15316+
if (bigint_cmp_zero(&val->data.x_bigint) != CmpLT) {
15317+
size_t result = bigint_popcount_unsigned(&val->data.x_bigint);
15318+
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
15319+
bigint_init_unsigned(&out_val->data.x_bigint, result);
15320+
return ira->codegen->builtin_types.entry_num_lit_int;
15321+
}
15322+
if (value->value.type->id == TypeTableEntryIdComptimeInt) {
15323+
Buf *val_buf = buf_alloc();
15324+
bigint_append_buf(val_buf, &val->data.x_bigint, 10);
15325+
ir_add_error(ira, &instruction->base,
15326+
buf_sprintf("@popCount on negative %s value %s",
15327+
buf_ptr(&value->value.type->name), buf_ptr(val_buf)));
15328+
return ira->codegen->builtin_types.entry_invalid;
15329+
}
15330+
size_t result = bigint_popcount_signed(&val->data.x_bigint, value->value.type->data.integral.bit_count);
15331+
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
15332+
bigint_init_unsigned(&out_val->data.x_bigint, result);
15333+
return ira->codegen->builtin_types.entry_num_lit_int;
15334+
}
15335+
15336+
IrInstruction *result = ir_build_pop_count(&ira->new_irb, instruction->base.scope,
15337+
instruction->base.source_node, value);
15338+
result->value.type = get_smallest_unsigned_int_type(ira->codegen, value->value.type->data.integral.bit_count);
15339+
ir_link_new_instruction(result, &instruction->base);
15340+
return result->value.type;
15341+
}
15342+
1527815343
static IrInstruction *ir_analyze_union_tag(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value) {
1527915344
if (type_is_invalid(value->value.type))
1528015345
return ira->codegen->invalid_instruction;
@@ -20534,6 +20599,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
2053420599
return ir_analyze_instruction_clz(ira, (IrInstructionClz *)instruction);
2053520600
case IrInstructionIdCtz:
2053620601
return ir_analyze_instruction_ctz(ira, (IrInstructionCtz *)instruction);
20602+
case IrInstructionIdPopCount:
20603+
return ir_analyze_instruction_pop_count(ira, (IrInstructionPopCount *)instruction);
2053720604
case IrInstructionIdSwitchBr:
2053820605
return ir_analyze_instruction_switch_br(ira, (IrInstructionSwitchBr *)instruction);
2053920606
case IrInstructionIdSwitchTarget:
@@ -20892,6 +20959,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2089220959
case IrInstructionIdUnwrapOptional:
2089320960
case IrInstructionIdClz:
2089420961
case IrInstructionIdCtz:
20962+
case IrInstructionIdPopCount:
2089520963
case IrInstructionIdSwitchVar:
2089620964
case IrInstructionIdSwitchTarget:
2089720965
case IrInstructionIdUnionTag:

src/ir_print.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,12 @@ static void ir_print_ctz(IrPrint *irp, IrInstructionCtz *instruction) {
501501
fprintf(irp->f, ")");
502502
}
503503

504+
static void ir_print_pop_count(IrPrint *irp, IrInstructionPopCount *instruction) {
505+
fprintf(irp->f, "@popCount(");
506+
ir_print_other_instruction(irp, instruction->value);
507+
fprintf(irp->f, ")");
508+
}
509+
504510
static void ir_print_switch_br(IrPrint *irp, IrInstructionSwitchBr *instruction) {
505511
fprintf(irp->f, "switch (");
506512
ir_print_other_instruction(irp, instruction->target_value);
@@ -1425,6 +1431,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
14251431
case IrInstructionIdCtz:
14261432
ir_print_ctz(irp, (IrInstructionCtz *)instruction);
14271433
break;
1434+
case IrInstructionIdPopCount:
1435+
ir_print_pop_count(irp, (IrInstructionPopCount *)instruction);
1436+
break;
14281437
case IrInstructionIdClz:
14291438
ir_print_clz(irp, (IrInstructionClz *)instruction);
14301439
break;

test/behavior.zig

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@ comptime {
88
_ = @import("cases/atomics.zig");
99
_ = @import("cases/bitcast.zig");
1010
_ = @import("cases/bool.zig");
11+
_ = @import("cases/bugs/1111.zig");
1112
_ = @import("cases/bugs/394.zig");
1213
_ = @import("cases/bugs/655.zig");
1314
_ = @import("cases/bugs/656.zig");
1415
_ = @import("cases/bugs/828.zig");
1516
_ = @import("cases/bugs/920.zig");
16-
_ = @import("cases/bugs/1111.zig");
1717
_ = @import("cases/byval_arg_var.zig");
1818
_ = @import("cases/cast.zig");
1919
_ = @import("cases/const_slice_child.zig");
20-
_ = @import("cases/coroutines.zig");
2120
_ = @import("cases/coroutine_await_struct.zig");
21+
_ = @import("cases/coroutines.zig");
2222
_ = @import("cases/defer.zig");
2323
_ = @import("cases/enum.zig");
2424
_ = @import("cases/enum_with_members.zig");
@@ -36,11 +36,12 @@ comptime {
3636
_ = @import("cases/math.zig");
3737
_ = @import("cases/merge_error_sets.zig");
3838
_ = @import("cases/misc.zig");
39-
_ = @import("cases/optional.zig");
4039
_ = @import("cases/namespace_depends_on_compile_var/index.zig");
4140
_ = @import("cases/new_stack_call.zig");
4241
_ = @import("cases/null.zig");
42+
_ = @import("cases/optional.zig");
4343
_ = @import("cases/pointers.zig");
44+
_ = @import("cases/popcount.zig");
4445
_ = @import("cases/pub_enum/index.zig");
4546
_ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig");
4647
_ = @import("cases/reflection.zig");

0 commit comments

Comments
 (0)