<rss version="2.0">
  <channel>
    <title>[we]blog</title>
    <link>https://weblog.0x51.dev</link>
    <description>[we]blog - Blog</description>
    <generator>Zine -- https://zine-ssg.io</generator>
    <language>en-US</language>
    <lastBuildDate>Fri, 24 Jul 2026 07:55:04 +0000</lastBuildDate>
    
      <item>
        <title>A Native AMDGCN Backend for Zig</title>
        <description>&lt;p&gt;This is the first post in a series I have no business starting.&lt;/p&gt;&lt;h2&gt;How I got here&lt;/h2&gt;&lt;p&gt;I’ve been poking at Zig’s native SPIR-V¹ backend. Not because I had a plan, but because that’s how I learn anything: I open a door, see a corridor, and forget what I came for. SPIR-V led to “how does a GPU actually receive code,” which led to “what does the machine code even look like,” which led to me staring at an AMD ISA² manual at an hour I’m not proud of.&lt;/p&gt;&lt;aside class=&quot;sidenote&quot;&gt;¹ Standard Portable Intermediate Representation - Khronos&apos;s binary IR that Vulkan and OpenCL hand to a driver in place of shader source.&lt;/aside&gt;
&lt;aside class=&quot;sidenote&quot;&gt;² Instruction Set Architecture: the exact set of machine instructions a chip runs, down to how each one is encoded into bytes.&lt;/aside&gt;
&lt;p&gt;Eventually I stopped and asked the obvious question:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Could Zig emit code for my GPU &lt;em&gt;directly&lt;/em&gt;, no LLVM, no SPIR-V, no intermediary, the way its self-hosted backends already do for x86_64 and aarch64?&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;And then, against my better judgement, I decided to find out.&lt;/p&gt;&lt;h2&gt;Why AMDGCN&lt;/h2&gt;&lt;p&gt;Two reasons, one principled and one entirely accidental.&lt;/p&gt;&lt;p&gt;The principled one: &lt;strong&gt;AMD is the open option.&lt;/strong&gt; The instruction set is documented in public whitepapers, the runtime (ROCm³) is open source, and the whole code-object format is specified rather than reverse-engineered. NVIDIA’s stack is a wall of closed PTX/SASS⁴ and a driver that guards the real ISA. If I’m going to hand-assemble GPU machine code to learn how it works, I’d like the manual to actually exist.&lt;/p&gt;&lt;aside class=&quot;sidenote&quot;&gt;³ Radeon Open Compute - AMD&apos;s open-source GPU compute stack (driver, runtime, libraries), the rough counterpart to NVIDIA&apos;s CUDA.&lt;/aside&gt;
&lt;aside class=&quot;sidenote&quot;&gt;⁴ PTX is NVIDIA&apos;s documented virtual ISA; SASS is the real per-GPU machine code it lowers to. Only PTX is public, and only partly.&lt;/aside&gt;
&lt;p&gt;The accidental one: &lt;strong&gt;I happen to own an all-AMD desktop.&lt;/strong&gt; I built it a while back without any of this in mind, and it turns out to be exactly the machine you want for this kind of masochism:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;GPU&lt;/strong&gt;: Radeon RX 7900 (Navi 31, &lt;code&gt;gfx1100&lt;/code&gt;, RDNA3, wave32)⁵&lt;/li&gt;&lt;li&gt;&lt;strong&gt;CPU&lt;/strong&gt;: Ryzen 7 7800X3D (8 cores / 16 threads)&lt;/li&gt;&lt;li&gt;&lt;strong&gt;RAM&lt;/strong&gt;: 64 GB&lt;/li&gt;&lt;li&gt;&lt;strong&gt;iGPU&lt;/strong&gt;: Raphael, riding along on the Ryzen&lt;/li&gt;&lt;/ul&gt;&lt;aside class=&quot;sidenote&quot;&gt;⁵ `gfx1100` is AMD&apos;s ISA name for this RDNA3 part; `wave32` means its threads execute in wavefronts of 32 lanes rather than the older 64.&lt;/aside&gt;
&lt;p&gt;So the target picks itself: &lt;code&gt;amdgcn-amd-amdhsa&lt;/code&gt;⁶, &lt;code&gt;gfx1100&lt;/code&gt;. One GPU generation, one code-object version.&lt;/p&gt;&lt;aside class=&quot;sidenote&quot;&gt;⁶ The target triple: `amdgcn` ISA, `amd` vendor, `amdhsa` OS/ABI - the HSA runtime&apos;s code-object and loader conventions.&lt;/aside&gt;
&lt;h2&gt;Where things actually stand&lt;/h2&gt;&lt;p&gt;I want to be honest about how little I’ve done, because the gap between “I started” and “it works” is the whole point of this series.&lt;/p&gt;&lt;p&gt;The compiler work I’ve actually landed so far was all on the SPIR-V side. While poking at Zig’s native SPIR-V backend I fixed a few very, very minor compiler errors, the kind that barely deserve a commit message, and got its test happy. That’s the rabbit hole that eventually spat me out in front of the AMDGCN question. None of it was AMDGCN work.&lt;/p&gt;&lt;p&gt;On the AMDGCN side the page is nearly blank. &lt;code&gt;amdgcn&lt;/code&gt; is already a real target architecture in the Zig compiler: it lives in the target tables, and &lt;code&gt;test/llvm_targets.zig&lt;/code&gt; already lists &lt;code&gt;amdgcn-amd-amdhsa&lt;/code&gt;. So the scaffolding for &lt;em&gt;talking about&lt;/em&gt; the target exists. What doesn’t exist, at all, is a native backend that turns Zig’s IR⁷ into AMD machine code without leaning on LLVM. That’s the thing I’m setting out to build.&lt;/p&gt;&lt;aside class=&quot;sidenote&quot;&gt;⁷ Intermediate Representation: the compiler&apos;s own instruction format, sitting between your source and machine code. A backend&apos;s job is to lower it to a specific ISA.&lt;/aside&gt;
&lt;h2&gt;This is going to be hard, and that’s fine&lt;/h2&gt;&lt;p&gt;I have no illusions here. A native GPU backend means understanding the ISA encoding, the 64-byte kernel descriptor, the metadata the loader reads, and the dispatch machinery: an entire stack that normally hides behind a compiler and a driver. It is genuinely difficult, and I will get a lot of it wrong in public.&lt;/p&gt;&lt;p&gt;But this was never about shipping a production backend. It’s a learning journey. If the destination turns out to be unreachable, I’ll have learned how GPUs boot code along the way, and that’s already worth the trip.&lt;/p&gt;&lt;p&gt;So I did the scariest part first: prove the AMD code-object format and loader by hand, with the compiler completely out of the loop. The smallest possible signal is an empty kernel that dispatches on real hardware without faulting.&lt;/p&gt;&lt;h2&gt;Milestone A: an empty kernel that dispatches&lt;/h2&gt;&lt;p&gt;Success here is nothing more than “it ran”: one workgroup, one lane, a completion signal that fires, no queue error and no page fault. That sounds trivial, but reaching it means the code-object format, the kernel descriptor, the loader, and the dispatch packet are all correct. That is most of the risk retired at once.&lt;/p&gt;&lt;h3&gt;A reference to copy&lt;/h3&gt;&lt;p&gt;Before writing anything by hand, I built a known-good template with clang:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;constant function&quot;&gt;clang&lt;/span&gt; &lt;span class=&quot;constant&quot;&gt;--target=amdgcn-amd-amdhsa&lt;/span&gt; &lt;span class=&quot;constant&quot;&gt;-mcpu=gfx1100&lt;/span&gt; &lt;span class=&quot;constant&quot;&gt;-mcode-object-version=5&lt;/span&gt; &lt;span class=&quot;constant&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;constant&quot;&gt;reference.c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Dumped with &lt;code&gt;llvm-objdump -d&lt;/code&gt; and &lt;code&gt;llvm-readobj --notes&lt;/code&gt;, it is not the deliverable but a correct example to diff against. The descriptor and the metadata note are fiddly enough that you want something known-good beside you rather than building blind.&lt;/p&gt;&lt;h3&gt;The three pieces of a code object&lt;/h3&gt;&lt;p&gt;A loadable AMD code object is an ELF⁸ for &lt;code&gt;amdgcn-amd-amdhsa&lt;/code&gt; with three things the loader cares about: the code, a 64-byte kernel descriptor⁹, and a metadata note.&lt;/p&gt;&lt;aside class=&quot;sidenote&quot;&gt;⁸ Executable and Linkable Format: the same container Linux uses for ordinary binaries. AMD reuses it for GPU code objects, sections, symbols, notes and all.&lt;/aside&gt;
&lt;aside class=&quot;sidenote&quot;&gt;⁹ A fixed 64-byte, bit-packed struct the loader reads to launch a kernel: register counts, segment sizes, entry point. One wrong bit and the dispatch faults.&lt;/aside&gt;
&lt;p&gt;The code is one instruction. &lt;code&gt;s_endpgm&lt;/code&gt; ends the wavefront, and it encodes to the four bytes &lt;code&gt;00 00 b0 bf&lt;/code&gt; on gfx1100. The descriptor is a bit-packed structure the assembler synthesizes from an &lt;code&gt;.amdhsa_kernel&lt;/code&gt; block; we ask for the bare minimum:&lt;/p&gt;&lt;p&gt;&lt;figure&gt;&lt;pre&gt;&lt;code class=&quot;asm&quot;&gt;&lt;span class=&quot;comment spell&quot;&gt;// The 64-byte kernel descriptor. The assembler synthesizes the bit-packed&lt;/span&gt;
&lt;span class=&quot;comment spell&quot;&gt;// COMPUTE_PGM_RSRC words from these fields; we ask for the bare minimum.&lt;/span&gt;
	&lt;span class=&quot;function_builtin&quot;&gt;.rodata&lt;/span&gt;
	.p2align	6              &lt;span class=&quot;comment spell&quot;&gt;// descriptor must be 64-byte aligned&lt;/span&gt;
	&lt;span class=&quot;function_builtin&quot;&gt;.amdhsa_kernel&lt;/span&gt; &lt;span class=&quot;variable_builtin&quot;&gt;empty_kernel&lt;/span&gt;
		&lt;span class=&quot;function_builtin&quot;&gt;.amdhsa_next_free_vgpr&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;
		&lt;span class=&quot;function_builtin&quot;&gt;.amdhsa_next_free_sgpr&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;
		.amdhsa_wavefront_size32 1
	&lt;span class=&quot;function_builtin&quot;&gt;.end_amdhsa_kernel&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;figcaption&gt;&lt;a href=&quot;https://codeberg.org/quint/zig-gpu/src/commit/306b4700eb5c89d5d4ac36f43bc70701b6ca5093/lab/milestone-a/s_endpgm.s#L18-L26&quot;&gt;s_endpgm.s:18-26&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;&lt;p&gt;That block also creates the symbol &lt;code&gt;empty_kernel.kd&lt;/code&gt;, which the loader hands back as the kernel object at dispatch time. The third piece is a msgpack¹⁰ &lt;code&gt;NT_AMDGPU_METADATA&lt;/code&gt; note, the loader’s directory: it names the kernel, points at its &lt;code&gt;.kd&lt;/code&gt; symbol, and declares the arguments and wavefront size.&lt;/p&gt;&lt;aside class=&quot;sidenote&quot;&gt;¹⁰ A compact binary serialization format, like JSON but bytes instead of text. AMD&apos;s loader reads kernel metadata from a msgpack blob stuffed into an ELF note.&lt;/aside&gt;
&lt;p&gt;&lt;figure&gt;&lt;pre&gt;&lt;code class=&quot;asm&quot;&gt;&lt;span class=&quot;comment spell&quot;&gt;// The msgpack metadata note the loader reads to find the kernel and its symbol.&lt;/span&gt;
	&lt;span class=&quot;function_builtin&quot;&gt;.amdgpu_metadata&lt;/span&gt;
&lt;span class=&quot;operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&lt;/span&gt;
&lt;span class=&quot;label&quot;&gt;amdhsa.version&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;operator&quot;&gt;-&lt;/span&gt; 1
  &lt;span class=&quot;operator&quot;&gt;-&lt;/span&gt; 2
&lt;span class=&quot;label&quot;&gt;amdhsa.target&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt; amdgcn&lt;span class=&quot;operator&quot;&gt;-&lt;/span&gt;amd&lt;span class=&quot;operator&quot;&gt;-&lt;/span&gt;amdhsa&lt;span class=&quot;operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&lt;/span&gt;gfx1100
&lt;span class=&quot;label&quot;&gt;amdhsa.kernels&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;function_builtin&quot;&gt;.name&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt;            &lt;span class=&quot;variable_builtin&quot;&gt;empty_kernel&lt;/span&gt;
    &lt;span class=&quot;function_builtin&quot;&gt;.symbol&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt;          empty_kernel.kd
    .kernarg_segment_size&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt; 0
    .kernarg_segment_align&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt; 4
    .group_segment_fixed_size&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt; 0
    .private_segment_fixed_size&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt; 0
    .sgpr_count&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt;      0
    .vgpr_count&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt;      0
    &lt;span class=&quot;function_builtin&quot;&gt;.max_flat_workgroup_size&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;1024&lt;/span&gt;
    &lt;span class=&quot;function_builtin&quot;&gt;.wavefront_size&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;number&quot;&gt;32&lt;/span&gt;
    .args&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt;            &lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;
...
	&lt;span class=&quot;function_builtin&quot;&gt;.end_amdgpu_metadata&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;figcaption&gt;&lt;a href=&quot;https://codeberg.org/quint/zig-gpu/src/commit/306b4700eb5c89d5d4ac36f43bc70701b6ca5093/lab/milestone-a/s_endpgm.s#L28-L48&quot;&gt;s_endpgm.s:28-48&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;&lt;h3&gt;Whose loader, whose dispatch?&lt;/h3&gt;&lt;p&gt;To put a kernel on the GPU you need some runtime to talk to the kernel driver. That is not a compromise of the no-LLVM goal, which is about codegen. The question is how much of the loading and dispatch we do ourselves. There’s a spectrum. HIP¹¹ hides everything behind &lt;code&gt;hipModuleLaunchKernel&lt;/code&gt;. Raw KFD¹² ioctls do it all by hand, no ROCm at all. In between sits HSA¹³, the low-level runtime HIP is built on.&lt;/p&gt;&lt;aside class=&quot;sidenote&quot;&gt;¹¹ Heterogeneous-compute Interface for Portability: AMD&apos;s high-level, CUDA-like C++ API. Convenient, but it hides exactly the machinery I want to see.&lt;/aside&gt;
&lt;aside class=&quot;sidenote&quot;&gt;¹² Kernel Fusion Driver: the amdgpu kernel driver&apos;s `ioctl` interface. The rawest option - no user-space runtime at all, just syscalls.&lt;/aside&gt;
&lt;aside class=&quot;sidenote&quot;&gt;¹³ Heterogeneous System Architecture: the open runtime standard HIP sits on top of. Low-level enough to build dispatch packets by hand, high enough to not write ioctls.&lt;/aside&gt;
&lt;p&gt;I chose HSA. Its loader parses the descriptor and metadata we wrote, so those get validated by something other than ourselves, but we still build the dispatch packet and ring the doorbell ourselves. That way “it ran” reflects our own understanding, not HIP’s.&lt;/p&gt;&lt;h3&gt;Building the dispatch packet by hand&lt;/h3&gt;&lt;p&gt;The host side is a small Zig program that talks to &lt;code&gt;libhsa-runtime64&lt;/code&gt;. It loads the code object, looks up &lt;code&gt;empty_kernel.kd&lt;/code&gt;, fills in an AQL¹⁴ kernel-dispatch packet field by field, publishes the header with a release fence so the packet processor only ever sees a fully-written packet, and rings the doorbell¹⁵:&lt;/p&gt;&lt;aside class=&quot;sidenote&quot;&gt;¹⁴ Architected Queuing Language - HSA&apos;s hardware packet format. You write dispatch packets into a ring buffer and the GPU&apos;s packet processor consumes them directly.&lt;/aside&gt;
&lt;aside class=&quot;sidenote&quot;&gt;¹⁵ A hardware register the GPU watches; writing the queue&apos;s new write-index to it signals the packet processor that work is waiting.&lt;/aside&gt;
&lt;p&gt;&lt;figure&gt;&lt;pre&gt;&lt;code class=&quot;zig&quot;&gt;    &lt;span class=&quot;comment_documentation comment spell&quot;&gt;// Reserve a slot and build the AQL kernel-dispatch packet BY HAND.&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;type constant variable_builtin function_call variable_member variable&quot;&gt;hsa_queue_add_write_index_relaxed&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;mask&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;type_builtin&quot;&gt;u64&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;module constant variable_builtin type variable&quot;&gt;packets&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;hsa_kernel_dispatch_packet_t&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;function_builtin keyword_import&quot;&gt;@ptrCast&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function_builtin&quot;&gt;@alignCast&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;base_address&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;pkt&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;packets&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;mask&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;pkt&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;.*&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;mem&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;type constant variable_builtin function_call variable_member variable&quot;&gt;zeroes&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;hsa_kernel_dispatch_packet_t&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    pkt&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;unnamed_0&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;unnamed_0&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;setup&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;function_builtin&quot;&gt;@as&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;type_builtin&quot;&gt;u16&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;function_builtin&quot;&gt;@as&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;type_builtin&quot;&gt;u4&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;function_builtin&quot;&gt;@intCast&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;HSA_KERNEL_DISPATCH_PACKET_SETUP_DIMENSIONS&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;comment_documentation comment spell&quot;&gt;// 1-D grid&lt;/span&gt;
    pkt&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;workgroup_size_x&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    pkt&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;workgroup_size_y&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    pkt&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;workgroup_size_z&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    pkt&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;grid_size_x&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    pkt&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;grid_size_y&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    pkt&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;grid_size_z&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    pkt&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;group_segment_size&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;group_size&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    pkt&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;private_segment_size&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;private_size&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    pkt&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;kernel_object&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;kernel_object&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    pkt&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;kernarg_address&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant_builtin&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;comment_documentation comment spell&quot;&gt;// no kernel arguments&lt;/span&gt;
    pkt&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;completion_signal&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;comment_documentation comment spell&quot;&gt;// Publish the header atomically (release) so the packet processor only ever&lt;/span&gt;
    &lt;span class=&quot;comment_documentation comment spell&quot;&gt;// observes a fully-written packet.&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; header&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt; u16 &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt;
        &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function_builtin&quot;&gt;@as&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;type_builtin&quot;&gt;u16&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;function_builtin&quot;&gt;@intCast&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;HSA_PACKET_TYPE_KERNEL_DISPATCH&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;PH_TYPE&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;|&lt;/span&gt;
        &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function_builtin&quot;&gt;@as&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;type_builtin&quot;&gt;u16&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;PH_BARRIER&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;|&lt;/span&gt;
        &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function_builtin&quot;&gt;@as&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;type_builtin&quot;&gt;u16&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;function_builtin&quot;&gt;@intCast&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;HSA_FENCE_SCOPE_SYSTEM&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;PH_ACQ&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;|&lt;/span&gt;
        &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function_builtin&quot;&gt;@as&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;type_builtin&quot;&gt;u16&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;function_builtin&quot;&gt;@intCast&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;HSA_FENCE_SCOPE_SYSTEM&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;PH_REL&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;function_builtin&quot;&gt;@atomicStore&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;type_builtin&quot;&gt;u16&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;function_builtin&quot;&gt;@as&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;type_builtin&quot;&gt;u16&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;function_builtin&quot;&gt;@ptrCast&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;pkt&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;comment_documentation comment spell&quot;&gt;// Ring the doorbell: tell the packet processor there&amp;apos;s work at `index`.&lt;/span&gt;
    &lt;span class=&quot;variable_builtin&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;type constant variable_builtin function_call variable_member variable&quot;&gt;hsa_queue_store_write_index_relaxed&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;variable_builtin&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;type constant variable_builtin function_call variable_member variable&quot;&gt;hsa_signal_store_relaxed&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;doorbell_signal&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;function_builtin&quot;&gt;@intCast&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    std&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;type constant variable_builtin function_call variable_member variable&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;doorbell rung, waiting for completion...&lt;/span&gt;&lt;span class=&quot;string string_escape&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;comment_documentation comment spell&quot;&gt;// Block until the kernel signals done.&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; v &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;type constant variable_builtin function_call variable_member variable&quot;&gt;hsa_signal_wait_scacquire&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;COND_EQ&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;type constant variable_builtin function_call variable_member variable&quot;&gt;maxInt&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;type_builtin&quot;&gt;u64&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;WAIT_BLOCKED&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    std&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;type constant variable_builtin function_call variable_member variable&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;completion signal = {d}&lt;/span&gt;&lt;span class=&quot;string string_escape&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    std&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;type constant variable_builtin function_call variable_member variable&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;DISPATCHED empty_kernel: 1 workgroup, 1 lane, no fault. it ran.&lt;/span&gt;&lt;span class=&quot;string string_escape&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;figcaption&gt;&lt;a href=&quot;https://codeberg.org/quint/zig-gpu/src/commit/306b4700eb5c89d5d4ac36f43bc70701b6ca5093/lab/milestone-a/dispatch.zig#L108-L145&quot;&gt;dispatch.zig:108-145&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;&lt;h3&gt;Detours&lt;/h3&gt;&lt;p&gt;&lt;code&gt;rocminfo&lt;/code&gt; refused to run, printing “ROCk module is NOT loaded”. That turned out to be cosmetic: it checks &lt;code&gt;/sys/module/amdgpu/initstate&lt;/code&gt;, which does not exist on this kernel. The HSA runtime itself initializes fine and sees &lt;code&gt;gfx1100&lt;/code&gt;, so the check is a quirk, not a real problem.&lt;/p&gt;&lt;h3&gt;It ran&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;GPU agent: gfx1100
executable frozen (loader accepted our descriptor + metadata)
doorbell rung, waiting for completion...
completion signal = 0
DISPATCHED empty_kernel: 1 workgroup, 1 lane, no fault. it ran.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The completion signal reaching zero is the whole ballgame. With the compiler nowhere in sight, we proved the code-object format, the kernel descriptor, the HSA loader, and a dispatch packet we built ourselves. Now we know exactly what the backend has to produce.&lt;/p&gt;&lt;p&gt;Next, the compiler finally enters the picture: the first job is to emit exactly this code object, but from inside Zig’s backend, driven by the compiler’s IR instead of hand-written assembly.&lt;/p&gt;</description>
        <link>https://weblog.0x51.dev/blog/a-native-amdgcn-backend-for-zig/</link>
        <pubDate>Fri, 03 Jul 2026 00:00:00 +0000</pubDate>
        <guid>https://weblog.0x51.dev/blog/a-native-amdgcn-backend-for-zig/</guid>
      </item>
    
      <item>
        <title>Taxonomies in Zine</title>
        <description>&lt;p&gt;Zine ships without a taxonomy system: there is no built-in way to say “collect every page tagged &lt;code&gt;zig&lt;/code&gt; onto a &lt;code&gt;/tags/zig/&lt;/code&gt; page.” I added one in a &lt;a href=&quot;https://github.com/q-uint/zine/tree/feat/taxonomies&quot;&gt;fork&lt;/a&gt;, and the surface area is small enough to read in a sitting.&lt;/p&gt;&lt;p&gt;A taxonomy is declared in the site config. The whole contract is three strings: the field to read, and the two layouts used to render the listing and the per-term pages.&lt;/p&gt;&lt;p&gt;&lt;figure&gt;&lt;pre&gt;&lt;code class=&quot;zig&quot;&gt;&lt;span class=&quot;keyword_modifier&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;TaxonomyConfig&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword_type&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;comment_documentation comment spell&quot;&gt;/// The name of the taxonomy. For &amp;quot;tags&amp;quot;, reads from page.tags.&lt;/span&gt;
    &lt;span class=&quot;comment_documentation comment spell&quot;&gt;/// For anything else, reads from page.custom.{name} (must be an array of strings).&lt;/span&gt;
    &lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;type_builtin&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;comment_documentation comment spell&quot;&gt;/// Layout for the taxonomy list page (e.g., /tags/)&lt;/span&gt;
    &lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;type_builtin&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;comment_documentation comment spell&quot;&gt;/// Layout for individual term pages (e.g., /tags/zig/)&lt;/span&gt;
    &lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;term_layout&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;type_builtin&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;figcaption&gt;&lt;a href=&quot;https://github.com/q-uint/zine/blob/eac08713d063586c161fca211533fea77c074b22/src/root.zig#L26-L34&quot;&gt;root.zig:26-34&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;&lt;p&gt;The name does double duty. &lt;code&gt;tags&lt;/code&gt; is special-cased to the built-in &lt;code&gt;page.tags&lt;/code&gt; field; any other name reads from &lt;code&gt;page.custom.{name}&lt;/code&gt;, which is how the same machinery powers a &lt;code&gt;series&lt;/code&gt; taxonomy without a single line of extra Zig. The value must be an array of strings, so &lt;code&gt;.custom = { .series = [&amp;quot;demo&amp;quot;] }&lt;/code&gt; works while a bare &lt;code&gt;.series = &amp;quot;demo&amp;quot;&lt;/code&gt; is silently ignored.¹&lt;/p&gt;&lt;aside class=&quot;sidenote&quot;&gt;¹ Silent rather than fatal on purpose: &lt;code&gt;custom&lt;/code&gt; is a free-form ziggy map, so Zine can&apos;t tell a stray &lt;code&gt;.series&lt;/code&gt; string was meant for a taxonomy from ordinary post metadata.&lt;/aside&gt;
&lt;p&gt;That branch lives in one function. Given a page and a taxonomy name, it returns the list of terms that page belongs to, or null when the field is absent or malformed.&lt;/p&gt;&lt;p&gt;&lt;figure&gt;&lt;pre&gt;&lt;code class=&quot;zig&quot;&gt;&lt;span class=&quot;keyword_modifier&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;keyword_function&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable function&quot;&gt;extractTermsFromPage&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;constant variable_builtin variable_parameter variable type&quot;&gt;gpa&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;Allocator&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;constant variable_builtin variable_parameter variable type&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;Page&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;constant variable_builtin variable_parameter variable type&quot;&gt;taxonomy_name&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;type_builtin&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;type_builtin&quot;&gt;u8&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;keyword_conditional&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;mem&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;type constant variable_builtin function_call variable_member variable&quot;&gt;eql&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;type_builtin&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;taxonomy_name&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;tags&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;keyword_return&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;keyword_conditional&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;tags&lt;/span&gt; &lt;span class=&quot;keyword_conditional&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;constant_builtin&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;comment_documentation comment spell&quot;&gt;// Read from page.custom&lt;/span&gt;
    &lt;span class=&quot;keyword_conditional&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;custom&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;kv&lt;/span&gt; &lt;span class=&quot;punctuation_delimiter&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;punctuation_bracket operator&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;constant variable_builtin variable_parameter variable type&quot;&gt;kv&lt;/span&gt;&lt;span class=&quot;punctuation_bracket operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;kv&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;type constant variable_builtin function_call variable_member variable&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;taxonomy_name&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword_operator&quot;&gt;orelse&lt;/span&gt; &lt;span class=&quot;keyword_return&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant_builtin&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;keyword_conditional&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;punctuation_delimiter&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;punctuation_bracket operator&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;constant variable_builtin variable_parameter variable type&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;punctuation_bracket operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;keyword_conditional&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword_return&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant_builtin&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
                    &lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;terms&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword_exception&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;gpa&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;type constant variable_builtin function_call variable_member variable&quot;&gt;alloc&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;type_builtin&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable_member variable&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
                    &lt;span class=&quot;keyword_repeat&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation_bracket operator&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;constant variable_builtin variable_parameter variable type&quot;&gt;elem&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant variable_builtin variable_parameter variable type&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;punctuation_bracket operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;keyword_conditional&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;elem&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
                            &lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;bytes&lt;/span&gt; &lt;span class=&quot;punctuation_delimiter&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;punctuation_bracket operator&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;constant variable_builtin variable_parameter variable type&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;punctuation_bracket operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;terms&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant variable_builtin type variable&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;keyword_conditional&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;punctuation_delimiter&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword_return&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant_builtin&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;
                    &lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;
                    &lt;span class=&quot;keyword_return&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant variable_builtin type variable&quot;&gt;terms&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;keyword_conditional&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;punctuation_delimiter&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword_return&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant_builtin&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;keyword_conditional&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;punctuation_delimiter&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword_return&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant_builtin&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;figcaption&gt;&lt;a href=&quot;https://github.com/q-uint/zine/blob/eac08713d063586c161fca211533fea77c074b22/src/context/utils.zig#L38-L68&quot;&gt;utils.zig:38-68&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;&lt;p&gt;Everything downstream, slugifying each term, bucketing pages, emitting synthetic &lt;code&gt;/series/&lt;/code&gt; and &lt;code&gt;/series/demo/&lt;/code&gt; pages, hangs off this list. The strictness is deliberate: a non-array or a non-string element returns null rather than guessing, so a typo in frontmatter drops the page out of the taxonomy instead of crashing the build.&lt;/p&gt;</description>
        <link>https://weblog.0x51.dev/blog/taxonomies-in-zine/</link>
        <pubDate>Mon, 08 Jun 2026 00:00:00 +0000</pubDate>
        <guid>https://weblog.0x51.dev/blog/taxonomies-in-zine/</guid>
      </item>
    
      <item>
        <title>Tax Test Two</title>
        <description>&lt;p&gt;Second taxonomy test post.&lt;/p&gt;</description>
        <link>https://weblog.0x51.dev/blog/tax-test-two/</link>
        <pubDate>Mon, 02 Mar 2026 00:00:00 +0000</pubDate>
        <guid>https://weblog.0x51.dev/blog/tax-test-two/</guid>
      </item>
    
      <item>
        <title>Tax Test One</title>
        <description>&lt;p&gt;First taxonomy test post.&lt;/p&gt;</description>
        <link>https://weblog.0x51.dev/blog/tax-test-one/</link>
        <pubDate>Sun, 01 Mar 2026 00:00:00 +0000</pubDate>
        <guid>https://weblog.0x51.dev/blog/tax-test-one/</guid>
      </item>
    
  </channel>
</rss>
