[{"data":1,"prerenderedAt":39},["ShallowReactive",2],{"chapter:kernels\u002Ffirst-kernel\u002Fkernel-macro.json":3},{"project":4,"route":5,"title":6,"titleHtml":7,"navTitle":6,"part":8,"sourcePath":9,"editUrl":10,"html":11,"toc":12,"hasMermaid":32,"prev":33,"next":36},"kernels","\u002Fkernels\u002Ffirst-kernel\u002Fkernel-macro","What #[kernel] Generates","What \u003Ccode>#[kernel]\u003C\u002Fcode> Generates","Your First Kernel","first-kernel\u002Fkernel-macro.md","https:\u002F\u002Fgithub.com\u002Fteenygrad\u002Fteenygrad\u002Fedit\u002Fmain\u002Fbooks\u002Fkernels\u002Fsrc\u002Ffirst-kernel\u002Fkernel-macro.md","\u003Cp>Chapter 5 used a type you never wrote:\u003C\u002Fp>\n\u003Cpre data-lang=\"rust\" class=\"shiki teeny-datasheet\" style=\"background-color:#16181a;color:#e6e8e3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF5F9E\">let\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\"> kernel \u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">=\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\"> VectorAdd\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">::&#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\">f32\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">>::\u003C\u002Fspan>\u003Cspan style=\"color:#7FB6D9\">new\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">(\u003C\u002Fspan>\u003Cspan style=\"color:#B79AD4\">BLOCK_SIZE\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ccode>#[kernel]\u003C\u002Fcode> generated it. This chapter is about what else it generated, because\nknowing that turns several confusing things into obvious ones.\u003C\u002Fp>\n\u003Ch2 id=\"the-three-outputs\">The three outputs\u003C\u002Fh2>\n\u003Cp>From one annotated function, the macro emits three items.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Your function, unchanged.\u003C\u002Fstrong> It compiles as ordinary Rust and is type-checked\nby the ordinary compiler. Nothing calls it. Its purpose is to be checked and to\nbe \u003Cem>read\u003C\u002Fem> — the macro converts its tokens back into a string, and that string is\nwhat the GPU compiler sees.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>A struct\u003C\u002Fstrong>, named by converting the function name to PascalCase:\n\u003Ccode>vector_add\u003C\u002Fcode> becomes \u003Ccode>VectorAdd\u003C\u002Fcode>. This is the thing you construct and pass\naround.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>A dispatcher\u003C\u002Fstrong>, but only if you asked for one with \u003Ccode>#[kernel(dtypes = [...])]\u003C\u002Fcode>\nor \u003Ccode>#[kernel(backward = ...)]\u003C\u002Fcode>. Chapter 15 covers it. Without those arguments,\nyou get two items, not three.\u003C\u002Fp>\n\u003Ch2 id=\"the-struct\">The struct\u003C\u002Fh2>\n\u003Cp>The generic parameters get split three ways. The \u003Ccode>Triton\u003C\u002Fcode> parameter disappears —\nit exists only to give the body its operations. Const generics become \u003Cstrong>runtime\nfields\u003C\u002Fstrong>. Everything else stays a type parameter.\u003C\u002Fp>\n\u003Cp>So \u003Ccode>vector_add&lt;T: Triton, D: Num, const BLOCK_SIZE: i32&gt;\u003C\u002Fcode> produces a\n\u003Ccode>VectorAdd&lt;D&gt;\u003C\u002Fcode> with these members:\u003C\u002Fp>\n\u003Cpre data-lang=\"rust\" class=\"shiki teeny-datasheet\" style=\"background-color:#16181a;color:#e6e8e3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF5F9E\">pub\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\"> name\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">:\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\"> &#x26;'\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\">static\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\"> str\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">,\u003C\u002Fspan>\u003Cspan style=\"color:#7F877D;font-style:italic\">          \u002F\u002F \"vector_add\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF5F9E\">pub\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\"> id\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\"> String\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">,\u003C\u002Fspan>\u003Cspan style=\"color:#7F877D;font-style:italic\">                  \u002F\u002F \"vector_add__f32__128\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF5F9E\">pub\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\"> block_size\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\"> i32\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">,\u003C\u002Fspan>\u003Cspan style=\"color:#7F877D;font-style:italic\">             \u002F\u002F from `const BLOCK_SIZE`, lowercased\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF5F9E\">pub\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\"> kernel_source\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\"> String\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">,\u003C\u002Fspan>\u003Cspan style=\"color:#7F877D;font-style:italic\">       \u002F\u002F your function, as text\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF5F9E\">pub\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\"> entry_point_source\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\"> String\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">,\u003C\u002Fspan>\u003Cspan style=\"color:#7F877D;font-style:italic\">  \u002F\u002F the wrapper, as text\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF5F9E\">pub\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\"> source\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\"> String\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">,\u003C\u002Fspan>\u003Cspan style=\"color:#7F877D;font-style:italic\">              \u002F\u002F the two joined\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Two details worth pinning down, because both bite.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Const generics are lowercased.\u003C\u002Fstrong> \u003Ccode>const BLOCK_SIZE\u003C\u002Fcode> becomes the field\n\u003Ccode>block_size\u003C\u002Fcode>, and a positional argument to \u003Ccode>new()\u003C\u002Fcode>. With one constant that is\nharmless. With four it is not:\u003C\u002Fp>\n\u003Cpre data-lang=\"rust\" class=\"shiki teeny-datasheet\" style=\"background-color:#16181a;color:#e6e8e3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6FBF98\">Conv2dBnSiluGemmForward\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">::&#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\">f32\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">>::\u003C\u002Fspan>\u003Cspan style=\"color:#7FB6D9\">new\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">(\u003C\u002Fspan>\u003Cspan style=\"color:#B79AD4\">BLOCK_M\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">,\u003C\u002Fspan>\u003Cspan style=\"color:#B79AD4\"> BLOCK_N\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">,\u003C\u002Fspan>\u003Cspan style=\"color:#B79AD4\"> BLOCK_K\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">,\u003C\u002Fspan>\u003Cspan style=\"color:#B79AD4\"> GROUP_M\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Nothing checks the order. They are all \u003Ccode>i32\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>\u003Ccode>id\u003C\u002Fcode> identifies the kernel.\u003C\u002Fstrong> It is the function name, the dtypes, and the\nconst values, joined by double underscores — \u003Ccode>vector_add__f32__128\u003C\u002Fcode>. Change the\nblock size and you get a different id, so a different compilation. That is why\none kernel with two block sizes is two compiled kernels.\u003C\u002Fp>\n\u003Cp>It is not, however, what names the files on disk. The cache uses a content hash:\u003C\u002Fp>\n\u003Cpre class=\"code-panel\" data-lang=\"text\">\u003Ccode>\u002Ftmp\u002Fteenyc_cache\u002Fvector_add_5f69418a643d1353dba2ce66de8ed3dc4e1644c0d9474da4517ed6e7d3f67ff9.o\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ccode>{name}_{sha256 of the source}\u003C\u002Fcode>, with three files per kernel — \u003Ccode>.o\u003C\u002Fcode> (the PTX,\ndespite the extension), \u003Ccode>.mlir\u003C\u002Fcode>, and \u003Ccode>.rs\u003C\u002Fcode> (the full generated source that\n\u003Ccode>teenyc\u003C\u002Fcode> was given). The readable \u003Ccode>id\u003C\u002Fcode> and the on-disk name are two different\nthings, and it is the hash you will be looking at.\u003C\u002Fp>\n\u003Cp>The struct also implements \u003Ccode>Kernel\u003C\u002Fcode>, whose \u003Ccode>Args\u003C\u002Fcode> associated type is the\nlaunch-argument tuple — \u003Ccode>(*mut f32, *mut f32, *mut f32, i32)\u003C\u002Fcode> for this kernel,\nderived from the function’s parameter list with \u003Ccode>T::Pointer&lt;D&gt;\u003C\u002Fcode> rewritten to a\nraw pointer.\u003C\u002Fp>\n\u003Ch2 id=\"the-entry-point\">The entry point\u003C\u002Fh2>\n\u003Cp>This is the part worth looking at properly, because it explains the shape of\neverything else.\u003C\u002Fp>\n\u003Cp>\u003Ccode>teenyc\u003C\u002Fcode> cannot call a generic Rust function. It needs one concrete symbol with\na C calling convention. So the macro writes one, as text, with the generic\nparameters filled in.\u003C\u002Fp>\n\u003Cp>Here is the real one, taken from the \u003Ccode>.rs\u003C\u002Fcode> file the Chapter 5 run left in the\ncache — the actual text \u003Ccode>teenyc\u003C\u002Fcode> compiled:\u003C\u002Fp>\n\u003Cpre data-lang=\"rust\" class=\"shiki teeny-datasheet\" style=\"background-color:#16181a;color:#e6e8e3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF5F9E\">use\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\"> triton\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">::\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\">llvm\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">::\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\">triton\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">::\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\">num\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">::*;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF5F9E\">use\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\"> triton\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">::\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\">llvm\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">::\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\">triton\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">::\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\">pointer\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">::\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\">LlvmPointer\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF5F9E\">type\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\"> LlvmTriton\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\"> triton\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">::\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\">llvm\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">::\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\">triton\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">::\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\">LlvmTriton\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#8A9088\">#[\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\">no_mangle\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF5F9E\">pub\u003C\u002Fspan>\u003Cspan style=\"color:#FF5F9E\"> extern\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#D8A76B\">C\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#FF5F9E\"> fn\u003C\u002Fspan>\u003Cspan style=\"color:#7FB6D9\"> vector_add_entry_point\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\">a_ptr\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">:\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\"> *\u003C\u002Fspan>\u003Cspan style=\"color:#FF5F9E\">mut\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\"> f32\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">,\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\"> b_ptr\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">:\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\"> *\u003C\u002Fspan>\u003Cspan style=\"color:#FF5F9E\">mut\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\"> f32\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">,\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\"> out_ptr\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">:\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\"> *\u003C\u002Fspan>\u003Cspan style=\"color:#FF5F9E\">mut\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\"> f32\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">,\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\"> n_elements\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\"> i32\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">)\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF5F9E\">    let\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\"> a_ptr \u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">=\u003C\u002Fspan>\u003Cspan style=\"color:#7FB6D9\"> LlvmPointer\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\">a_ptr \u003C\u002Fspan>\u003Cspan style=\"color:#FF5F9E\">as\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\"> *\u003C\u002Fspan>\u003Cspan style=\"color:#FF5F9E\">mut\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\"> _\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF5F9E\">    let\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\"> b_ptr \u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">=\u003C\u002Fspan>\u003Cspan style=\"color:#7FB6D9\"> LlvmPointer\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\">b_ptr \u003C\u002Fspan>\u003Cspan style=\"color:#FF5F9E\">as\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\"> *\u003C\u002Fspan>\u003Cspan style=\"color:#FF5F9E\">mut\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\"> _\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF5F9E\">    let\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\"> out_ptr \u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">=\u003C\u002Fspan>\u003Cspan style=\"color:#7FB6D9\"> LlvmPointer\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\">out_ptr \u003C\u002Fspan>\u003Cspan style=\"color:#FF5F9E\">as\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\"> *\u003C\u002Fspan>\u003Cspan style=\"color:#FF5F9E\">mut\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\"> _\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#7FB6D9\">    vector_add\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">::&#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\">LlvmTriton\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">,\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\"> f32\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">,\u003C\u002Fspan>\u003Cspan style=\"color:#B79AD4\"> 128\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">>(\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\">a_ptr\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">,\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\"> b_ptr\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">,\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\"> out_ptr\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">,\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\"> n_elements\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#8A9088\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Those are the last eight lines of a 3,068-line file. The rest is the DSL itself,\nspliced in ahead of your kernel — which is what “compiled against a small\ngenerated environment” from Chapter 3 means in practice.\u003C\u002Fp>\n\u003Cp>Read the last line of the wrapper first:\u003C\u002Fp>\n\u003Cpre data-lang=\"rust\" class=\"shiki teeny-datasheet\" style=\"background-color:#16181a;color:#e6e8e3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#7FB6D9\">vector_add\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">::&#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\">LlvmTriton\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">,\u003C\u002Fspan>\u003Cspan style=\"color:#6FBF98\"> f32\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">,\u003C\u002Fspan>\u003Cspan style=\"color:#B79AD4\"> 128\u003C\u002Fspan>\u003Cspan style=\"color:#8A9088\">>(...)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>There it is. \u003Ccode>T\u003C\u002Fcode> is \u003Ccode>LlvmTriton\u003C\u002Fcode>, the implementation of the \u003Ccode>Triton\u003C\u002Fcode> trait that\nknows how to emit GPU operations. \u003Ccode>D\u003C\u002Fcode> is \u003Ccode>f32\u003C\u002Fcode>. And \u003Ccode>BLOCK_SIZE\u003C\u002Fcode> is \u003Ccode>128\u003C\u002Fcode> — a\nliteral, in the source text, exactly as Chapter 6 said it must be.\u003C\u002Fp>\n\u003Cp>The rest:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>\u003Ccode>#[no_mangle]\u003C\u002Fcode> and \u003Ccode>extern &quot;C&quot;\u003C\u002Fcode>\u003C\u002Fstrong> give a symbol with a predictable name,\n\u003Ccode>{function name}_entry_point\u003C\u002Fcode>, which is what the loader looks up in the PTX.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>The pointer rewrapping\u003C\u002Fstrong> turns the raw \u003Ccode>*mut f32\u003C\u002Fcode> the C ABI can carry into\nthe \u003Ccode>LlvmPointer\u003C\u002Fcode> the DSL works with. Three lines of ceremony you never see.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>The parameters\u003C\u002Fstrong> are your parameters, in order. This is the contract behind\nthe tuple you pass to \u003Ccode>launch\u003C\u002Fcode>: position for position, nothing checked.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"why-your-kernel-is-generic\">Why your kernel is generic\u003C\u002Fh2>\n\u003Cp>The \u003Ccode>T: Triton\u003C\u002Fcode> parameter now makes sense. It is not there for you.\u003C\u002Fp>\n\u003Cp>It is there so the \u003Cem>same source text\u003C\u002Fem> can be compiled twice: once by rustc, with\n\u003Ccode>T\u003C\u002Fcode> as an abstract type parameter, which is what type-checks your kernel; and\nonce by \u003Ccode>teenyc\u003C\u002Fcode>, with \u003Ccode>T\u003C\u002Fcode> as \u003Ccode>LlvmTriton\u003C\u002Fcode>, which is what emits GPU code.\u003C\u002Fp>\n\u003Cp>One function, two compilers, two meanings of \u003Ccode>T\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"seeing-it-yourself\">Seeing it yourself\u003C\u002Fh2>\n\u003Cpre data-lang=\"bash\" class=\"shiki teeny-datasheet\" style=\"background-color:#16181a;color:#e6e8e3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#7FB6D9\">cargo\u003C\u002Fspan>\u003Cspan style=\"color:#D8A76B\"> expand\u003C\u002Fspan>\u003Cspan style=\"color:#B79AD4\"> -p\u003C\u002Fspan>\u003Cspan style=\"color:#D8A76B\"> teeny-triton\u003C\u002Fspan>\u003Cspan style=\"color:#B79AD4\"> --example\u003C\u002Fspan>\u003Cspan style=\"color:#D8A76B\"> vector_add\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>That prints everything the macro produced. It is worth doing once. The generated\nsource strings appear as one long escaped literal, which is ugly but is exactly\nwhat gets compiled.\u003C\u002Fp>\n\u003Cp>The easier route is to run the kernel and read the \u003Ccode>.rs\u003C\u002Fcode> file it leaves in the\ncache — same content, already unescaped, alongside the \u003Ccode>.mlir\u003C\u002Fcode> and the PTX:\u003C\u002Fp>\n\u003Cpre data-lang=\"bash\" class=\"shiki teeny-datasheet\" style=\"background-color:#16181a;color:#e6e8e3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#7FB6D9\">ls\u003C\u002Fspan>\u003Cspan style=\"color:#E6E8E3\"> $TEENYC_CACHE_DIR    \u003C\u002Fspan>\u003Cspan style=\"color:#7F877D;font-style:italic\"># or \u002Ftmp\u002Fteenyc_cache\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"the-consequences-collected\">The consequences, collected\u003C\u002Fh2>\n\u003Cp>Everything below follows from the above, and each has bitten someone:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>You cannot call helper functions from a kernel body\u003C\u002Fstrong> unless they are part of\nthe DSL. Your crate is not in scope where the captured text is compiled.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Combine functions must be \u003Ccode>fn\u003C\u002Fcode> pointers, not closures.\u003C\u002Fstrong> A closure that\ncaptured a variable could not be written out as text. Chapter 13.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>The struct’s field names differ from the generic names.\u003C\u002Fstrong> \u003Ccode>BLOCK_SIZE\u003C\u002Fcode> →\n\u003Ccode>block_size\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Changing a constant recompiles.\u003C\u002Fstrong> Different id, different cache entry.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>A \u003Ccode>#[kernel]\u003C\u002Fcode> fn is callable from Rust and does nothing useful if you call\nit.\u003C\u002Fstrong> Nothing warns you.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Next: watching it happen, by reading what came out.\u003C\u002Fp>\n",[13,17,20,23,26,29],{"id":14,"text":15,"level":16},"the-three-outputs","The three outputs",2,{"id":18,"text":19,"level":16},"the-struct","The struct",{"id":21,"text":22,"level":16},"the-entry-point","The entry point",{"id":24,"text":25,"level":16},"why-your-kernel-is-generic","Why your kernel is generic",{"id":27,"text":28,"level":16},"seeing-it-yourself","Seeing it yourself",{"id":30,"text":31,"level":16},"the-consequences-collected","The consequences, collected",false,{"title":34,"titleHtml":34,"route":35},"Loads, Stores, and Masks","\u002Fkernels\u002Ffirst-kernel\u002Floads-stores-masks",{"title":37,"titleHtml":37,"route":38},"Compiling and Reading the Output","\u002Fkernels\u002Ffirst-kernel\u002Fcompiling",1786271829686]