Skip to content

Old Generator Documentation

Steven Johnson edited this page Oct 25, 2016 · 2 revisions

(This wiki page simply captures the documentation for Generator prior to https://github.com/halide/Halide/pull/1523 landing, and is here as a convenience for readers looking to understand older code. We recommend that all new code follow the current documentation.)

Generator is a class used to encapsulate the building of Funcs in user pipelines. A Generator is agnostic to JIT vs AOT compilation; it can be used for either purpose, but is especially convenient to use for AOT compilation.

A Generator automatically detects the run-time parameters (Param/ImageParams) associated with the Func and (for AOT code) produces a function signature with the correct params in the correct order.

A Generator can also be customized via compile-time parameters (GeneratorParams), which affect code generation.

GeneratorParams, ImageParams, and Params are (by convention) always public and always declared at the top of the Generator class, in the order

 GeneratorParam(s)
 ImageParam(s)
 Param(s)

Preferred style is to use C++11 in-class initialization style, e.g.

 GeneratorParam<int> magic{"magic", 42};

Note that the ImageParams/Params will appear in the C function call in the order they are declared. (GeneratorParams are always referenced by name, not position, so their order is irrelevant.)

All Param variants declared as Generator members must have explicit names, and all such names must match the regex [A-Za-z][A-Za-z_0-9]* (i.e., essentially a C/C++ variable name, with some extra restrictions on underscore use). By convention, the name should match the member-variable name.

Generators are usually added to a global registry to simplify AOT build mechanics; this is done by simply defining an instance of RegisterGenerator at static scope:

 RegisterGenerator<ExampleGen> register_jit_example{"jit_example"};

The registered name of the Generator is provided as an argument (which must match the same rules as Param names, above).

(If you are jitting, you may not need to bother registering your Generator, but it's considered best practice to always do so anyway.)

Most Generator classes will only need to provide a build() method that the base class will call, and perhaps declare a Param and/or GeneratorParam:

   class XorImage : public Generator<XorImage> {
   public:
       GeneratorParam<int> channels{"channels", 3};
       ImageParam input{UInt(8), 3, "input"};
       Param<uint8_t> mask{"mask"};

       Func build() {
           Var x, y, c;
           Func f;
           f(x, y, c) = input(x, y, c) ^ mask;
           f.bound(c, 0, bound).reorder(c, x, y).unroll(c);
           return f;
       }
   };
   RegisterGenerator<XorImage> reg_xor{"xor_image"};

By default, this code schedules itself for 3-channel (RGB) images; by changing the value of the "channels" GeneratorParam before calling build() we can produce code suited for different channel counts.

Note that a Generator is always executed with a specific Target assigned to it, that you can access via the get_target() method. (You should not use the global get_target_from_environment(), etc. methods provided in Target.h)

Your build() method will usually return a Func. If you have a pipeline that outputs multiple Funcs, you can also return a Pipeline object.