Halide
Pipeline.h
Go to the documentation of this file.
1 #ifndef HALIDE_PIPELINE_H
2 #define HALIDE_PIPELINE_H
3 
4 /** \file
5  *
6  * Defines the front-end class representing an entire Halide imaging
7  * pipeline.
8  */
9 
10 #include <vector>
11 
12 #include "AutoSchedule.h"
13 #include "ExternalCode.h"
14 #include "IntrusivePtr.h"
15 #include "JITModule.h"
16 #include "Module.h"
17 #include "Tuple.h"
18 #include "Target.h"
19 
20 namespace Halide {
21 
22 struct Argument;
23 class Func;
24 struct Outputs;
25 struct PipelineContents;
26 
27 namespace Internal {
28 class IRMutator2;
29 } // namespace Internal
30 
31 /**
32  * Used to determine if the output printed to file should be as a normal string
33  * or as an HTML file which can be opened in a browerser and manipulated via JS and CSS.*/
37 };
38 
39 namespace {
40 // Helper for deleting custom lowering passes. In the header so that
41 // it goes in user code on windows, where you can have multiple heaps.
42 template<typename T>
43 void delete_lowering_pass(T *pass) {
44  delete pass;
45 }
46 } // namespace
47 
48 /** A custom lowering pass. See Pipeline::add_custom_lowering_pass. */
51  void (*deleter)(Internal::IRMutator2 *);
52 };
53 
54 struct JITExtern;
55 
56 /** A class representing a Halide pipeline. Constructed from the Func
57  * or Funcs that it outputs. */
58 class Pipeline {
60 
61  std::vector<Argument> infer_arguments(Internal::Stmt body);
62  std::vector<const void *> prepare_jit_call_arguments(Realization dst, const Target &target);
63 
64  static std::vector<Internal::JITModule> make_externs_jit_module(const Target &target,
65  std::map<std::string, JITExtern> &externs_in_out);
66 
67 public:
68  /** Make an undefined Pipeline object. */
69  EXPORT Pipeline();
70 
71  /** Make a pipeline that computes the given Func. Schedules the
72  * Func compute_root(). */
73  EXPORT Pipeline(Func output);
74 
75  /** Make a pipeline that computes the givens Funcs as
76  * outputs. Schedules the Funcs compute_root(). */
77  EXPORT Pipeline(const std::vector<Func> &outputs);
78 
79  /** Get the Funcs this pipeline outputs. */
80  EXPORT std::vector<Func> outputs() const;
81 
82  /** Generate a schedule for the pipeline. */
83  //@{
84  EXPORT std::string auto_schedule(const Target &target,
85  const MachineParams &arch_params = MachineParams::generic());
86  //@}
87 
88  /** Return handle to the index-th Func within the pipeline based on the
89  * realization order. */
90  EXPORT Func get_func(size_t index);
91 
92  /** Compile and generate multiple target files with single call.
93  * Deduces target files based on filenames specified in
94  * output_files struct.
95  */
96  EXPORT void compile_to(const Outputs &output_files,
97  const std::vector<Argument> &args,
98  const std::string &fn_name,
99  const Target &target);
100 
101  /** Statically compile a pipeline to llvm bitcode, with the given
102  * filename (which should probably end in .bc), type signature,
103  * and C function name. If you're compiling a pipeline with a
104  * single output Func, see also Func::compile_to_bitcode. */
105  EXPORT void compile_to_bitcode(const std::string &filename,
106  const std::vector<Argument> &args,
107  const std::string &fn_name,
108  const Target &target = get_target_from_environment());
109 
110  /** Statically compile a pipeline to llvm assembly, with the given
111  * filename (which should probably end in .ll), type signature,
112  * and C function name. If you're compiling a pipeline with a
113  * single output Func, see also Func::compile_to_llvm_assembly. */
114  EXPORT void compile_to_llvm_assembly(const std::string &filename,
115  const std::vector<Argument> &args,
116  const std::string &fn_name,
117  const Target &target = get_target_from_environment());
118 
119  /** Statically compile a pipeline with multiple output functions to an
120  * object file, with the given filename (which should probably end in
121  * .o or .obj), type signature, and C function name (which defaults to
122  * the same name as this halide function. You probably don't want to
123  * use this directly; call compile_to_static_library or compile_to_file instead. */
124  EXPORT void compile_to_object(const std::string &filename,
125  const std::vector<Argument> &,
126  const std::string &fn_name,
127  const Target &target = get_target_from_environment());
128 
129  /** Emit a header file with the given filename for a pipeline. The
130  * header will define a function with the type signature given by
131  * the second argument, and a name given by the third. You don't
132  * actually have to have defined any of these functions yet to
133  * call this. You probably don't want to use this directly; call
134  * compile_to_static_library or compile_to_file instead. */
135  EXPORT void compile_to_header(const std::string &filename,
136  const std::vector<Argument> &,
137  const std::string &fn_name,
138  const Target &target = get_target_from_environment());
139 
140  /** Statically compile a pipeline to text assembly equivalent to
141  * the object file generated by compile_to_object. This is useful
142  * for checking what Halide is producing without having to
143  * disassemble anything, or if you need to feed the assembly into
144  * some custom toolchain to produce an object file. */
145  EXPORT void compile_to_assembly(const std::string &filename,
146  const std::vector<Argument> &args,
147  const std::string &fn_name,
148  const Target &target = get_target_from_environment());
149 
150  /** Statically compile a pipeline to C source code. This is useful
151  * for providing fallback code paths that will compile on many
152  * platforms. Vectorization will fail, and parallelization will
153  * produce serial code. */
154  EXPORT void compile_to_c(const std::string &filename,
155  const std::vector<Argument> &,
156  const std::string &fn_name,
157  const Target &target = get_target_from_environment());
158 
159  /** Write out an internal representation of lowered code. Useful
160  * for analyzing and debugging scheduling. Can emit html or plain
161  * text. */
162  EXPORT void compile_to_lowered_stmt(const std::string &filename,
163  const std::vector<Argument> &args,
164  StmtOutputFormat fmt = Text,
165  const Target &target = get_target_from_environment());
166 
167  /** Write out the loop nests specified by the schedule for this
168  * Pipeline's Funcs. Helpful for understanding what a schedule is
169  * doing. */
170  EXPORT void print_loop_nest();
171 
172  /** Compile to object file and header pair, with the given
173  * arguments. */
174  EXPORT void compile_to_file(const std::string &filename_prefix,
175  const std::vector<Argument> &args,
176  const std::string &fn_name,
177  const Target &target = get_target_from_environment());
178 
179  /** Compile to static-library file and header pair, with the given
180  * arguments. */
181  EXPORT void compile_to_static_library(const std::string &filename_prefix,
182  const std::vector<Argument> &args,
183  const std::string &fn_name,
184  const Target &target = get_target_from_environment());
185 
186  /** Compile to static-library file and header pair once for each target;
187  * each resulting function will be considered (in order) via halide_can_use_target_features()
188  * at runtime, with the first appropriate match being selected for subsequent use.
189  * This is typically useful for specializations that may vary unpredictably by machine
190  * (e.g., SSE4.1/AVX/AVX2 on x86 desktop machines).
191  * All targets must have identical arch-os-bits.
192  */
193  EXPORT void compile_to_multitarget_static_library(const std::string &filename_prefix,
194  const std::vector<Argument> &args,
195  const std::vector<Target> &targets);
196 
197  /** Create an internal representation of lowered code as a self
198  * contained Module suitable for further compilation. */
199  EXPORT Module compile_to_module(const std::vector<Argument> &args,
200  const std::string &fn_name,
201  const Target &target = get_target_from_environment(),
203 
204  /** Eagerly jit compile the function to machine code. This
205  * normally happens on the first call to realize. If you're
206  * running your halide pipeline inside time-sensitive code and
207  * wish to avoid including the time taken to compile a pipeline,
208  * then you can call this ahead of time. Returns the raw function
209  * pointer to the compiled pipeline. Default is to use the Target
210  * returned from Halide::get_jit_target_from_environment()
211  */
212  EXPORT void *compile_jit(const Target &target = get_jit_target_from_environment());
213 
214  /** Set the error handler function that be called in the case of
215  * runtime errors during halide pipelines. If you are compiling
216  * statically, you can also just define your own function with
217  * signature
218  \code
219  extern "C" void halide_error(void *user_context, const char *);
220  \endcode
221  * This will clobber Halide's version.
222  */
223  EXPORT void set_error_handler(void (*handler)(void *, const char *));
224 
225  /** Set a custom malloc and free for halide to use. Malloc should
226  * return 32-byte aligned chunks of memory, and it should be safe
227  * for Halide to read slightly out of bounds (up to 8 bytes before
228  * the start or beyond the end). If compiling statically, routines
229  * with appropriate signatures can be provided directly
230  \code
231  extern "C" void *halide_malloc(void *, size_t)
232  extern "C" void halide_free(void *, void *)
233  \endcode
234  * These will clobber Halide's versions. See \file HalideRuntime.h
235  * for declarations.
236  */
237  EXPORT void set_custom_allocator(void *(*malloc)(void *, size_t),
238  void (*free)(void *, void *));
239 
240  /** Set a custom task handler to be called by the parallel for
241  * loop. It is useful to set this if you want to do some
242  * additional bookkeeping at the granularity of parallel
243  * tasks. The default implementation does this:
244  \code
245  extern "C" int halide_do_task(void *user_context,
246  int (*f)(void *, int, uint8_t *),
247  int idx, uint8_t *state) {
248  return f(user_context, idx, state);
249  }
250  \endcode
251  * If you are statically compiling, you can also just define your
252  * own version of the above function, and it will clobber Halide's
253  * version.
254  *
255  * If you're trying to use a custom parallel runtime, you probably
256  * don't want to call this. See instead \ref Func::set_custom_do_par_for .
257  */
258  EXPORT void set_custom_do_task(
259  int (*custom_do_task)(void *, int (*)(void *, int, uint8_t *),
260  int, uint8_t *));
261 
262  /** Set a custom parallel for loop launcher. Useful if your app
263  * already manages a thread pool. The default implementation is
264  * equivalent to this:
265  \code
266  extern "C" int halide_do_par_for(void *user_context,
267  int (*f)(void *, int, uint8_t *),
268  int min, int extent, uint8_t *state) {
269  int exit_status = 0;
270  parallel for (int idx = min; idx < min+extent; idx++) {
271  int job_status = halide_do_task(user_context, f, idx, state);
272  if (job_status) exit_status = job_status;
273  }
274  return exit_status;
275  }
276  \endcode
277  *
278  * However, notwithstanding the above example code, if one task
279  * fails, we may skip over other tasks, and if two tasks return
280  * different error codes, we may select one arbitrarily to return.
281  *
282  * If you are statically compiling, you can also just define your
283  * own version of the above function, and it will clobber Halide's
284  * version.
285  */
286  EXPORT void set_custom_do_par_for(
287  int (*custom_do_par_for)(void *, int (*)(void *, int, uint8_t *), int,
288  int, uint8_t *));
289 
290  /** Set custom routines to call when tracing is enabled. Call this
291  * on the output Func of your pipeline. This then sets custom
292  * routines for the entire pipeline, not just calls to this
293  * Func.
294  *
295  * If you are statically compiling, you can also just define your
296  * own versions of the tracing functions (see HalideRuntime.h),
297  * and they will clobber Halide's versions. */
298  EXPORT void set_custom_trace(int (*trace_fn)(void *, const halide_trace_event_t *));
299 
300  /** Set the function called to print messages from the runtime.
301  * If you are compiling statically, you can also just define your
302  * own function with signature
303  \code
304  extern "C" void halide_print(void *user_context, const char *);
305  \endcode
306  * This will clobber Halide's version.
307  */
308  EXPORT void set_custom_print(void (*handler)(void *, const char *));
309 
310  /** Install a set of external C functions or Funcs to satisfy
311  * dependencies introduced by HalideExtern and define_extern
312  * mechanisms. These will be used by calls to realize,
313  * infer_bounds, and compile_jit. */
314  EXPORT void set_jit_externs(const std::map<std::string, JITExtern> &externs);
315 
316  /** Return the map of previously installed externs. Is an empty
317  * map unless set otherwise. */
318  EXPORT const std::map<std::string, JITExtern> &get_jit_externs();
319 
320  /** Get a struct containing the currently set custom functions
321  * used by JIT. */
322  EXPORT const Internal::JITHandlers &jit_handlers();
323 
324  /** Add a custom pass to be used during lowering. It is run after
325  * all other lowering passes. Can be used to verify properties of
326  * the lowered Stmt, instrument it with extra code, or otherwise
327  * modify it. The Func takes ownership of the pass, and will call
328  * delete on it when the Func goes out of scope. So don't pass a
329  * stack object, or share pass instances between multiple
330  * Funcs. */
331  template<typename T>
332  void add_custom_lowering_pass(T *pass) {
333  // Template instantiate a custom deleter for this type, then
334  // cast it to a deleter that takes a IRMutator2 *. The custom
335  // deleter lives in user code, so that deletion is on the same
336  // heap as construction (I hate Windows).
337  void (*deleter)(Internal::IRMutator2 *) =
338  (void (*)(Internal::IRMutator2 *))(&delete_lowering_pass<T>);
339  add_custom_lowering_pass(pass, deleter);
340  }
341 
342  /** Add a custom pass to be used during lowering, with the
343  * function that will be called to delete it also passed in. Set
344  * it to nullptr if you wish to retain ownership of the object. */
345  EXPORT void add_custom_lowering_pass(Internal::IRMutator2 *pass,
346  void (*deleter)(Internal::IRMutator2 *));
347 
348  /** Remove all previously-set custom lowering passes */
349  EXPORT void clear_custom_lowering_passes();
350 
351  /** Get the custom lowering passes. */
352  EXPORT const std::vector<CustomLoweringPass> &custom_lowering_passes();
353 
354  /** See Func::realize */
355  // @{
356  EXPORT Realization realize(std::vector<int32_t> sizes, const Target &target = Target());
357  EXPORT Realization realize(int x_size, int y_size, int z_size, int w_size,
358  const Target &target = Target());
359  EXPORT Realization realize(int x_size, int y_size, int z_size,
360  const Target &target = Target());
361  EXPORT Realization realize(int x_size, int y_size,
362  const Target &target = Target());
363  EXPORT Realization realize(int x_size,
364  const Target &target = Target());
365  EXPORT Realization realize(const Target &target = Target());
366  // @}
367 
368  /** Evaluate this Pipeline into an existing allocated buffer or
369  * buffers. If the buffer is also one of the arguments to the
370  * function, strange things may happen, as the pipeline isn't
371  * necessarily safe to run in-place. The realization should
372  * contain one Buffer per tuple component per output Func. For
373  * each individual output Func, all Buffers must have the same
374  * shape, but the shape can vary across the different output
375  * Funcs. This form of realize does *not* automatically copy data
376  * back from the GPU. */
377  EXPORT void realize(Realization dst, const Target &target = Target());
378 
379  /** For a given size of output, or a given set of output buffers,
380  * determine the bounds required of all unbound ImageParams
381  * referenced. Communicates the result by allocating new buffers
382  * of the appropriate size and binding them to the unbound
383  * ImageParams. */
384  // @{
385  EXPORT void infer_input_bounds(int x_size = 0, int y_size = 0, int z_size = 0, int w_size = 0);
386  EXPORT void infer_input_bounds(Realization dst);
387  // @}
388 
389  /** Infer the arguments to the Pipeline, sorted into a canonical order:
390  * all buffers (sorted alphabetically by name), followed by all non-buffers
391  * (sorted alphabetically by name).
392  This lets you write things like:
393  \code
394  pipeline.compile_to_assembly("/dev/stdout", pipeline.infer_arguments());
395  \endcode
396  */
397  EXPORT std::vector<Argument> infer_arguments();
398 
399  /** Check if this pipeline object is defined. That is, does it
400  * have any outputs? */
401  EXPORT bool defined() const;
402 
403  /** Invalidate any internal cached state, e.g. because Funcs have
404  * been rescheduled. */
405  EXPORT void invalidate_cache();
406 
407 private:
408  std::string generate_function_name() const;
409 };
410 
412 private:
413  Type ret_type_; // Only meaningful if is_void_return is false; must be default value otherwise
414  bool is_void_return_{false};
415  std::vector<Type> arg_types_;
416 
417 public:
418  ExternSignature() = default;
419 
420  ExternSignature(const Type &ret_type, bool is_void_return, const std::vector<Type> &arg_types)
421  : ret_type_(ret_type),
422  is_void_return_(is_void_return),
423  arg_types_(arg_types) {
424  internal_assert(!(is_void_return && ret_type != Type()));
425  }
426 
427  template <typename RT, typename... Args>
428  ExternSignature(RT (*f)(Args... args))
429  : ret_type_(type_of<RT>()),
430  is_void_return_(std::is_void<RT>::value),
431  arg_types_({type_of<Args>()...}) {
432  }
433 
434  const Type &ret_type() const {
435  internal_assert(!is_void_return());
436  return ret_type_;
437  }
438 
439  bool is_void_return() const {
440  return is_void_return_;
441  }
442 
443  const std::vector<Type> &arg_types() const {
444  return arg_types_;
445  }
446 };
447 
449 private:
450  void *address_{nullptr};
451  ExternSignature signature_;
452 
453 public:
454  ExternCFunction() = default;
455 
456  ExternCFunction(void *address, const ExternSignature &signature)
457  : address_(address), signature_(signature) {}
458 
459  template <typename RT, typename... Args>
460  ExternCFunction(RT (*f)(Args... args)) : ExternCFunction((void *)f, ExternSignature(f)) {}
461 
462  void *address() const { return address_; }
463  const ExternSignature &signature() const { return signature_; }
464 };
465 
466 struct JITExtern {
467 private:
468  // Note that exactly one of pipeline_ and extern_c_function_
469  // can be set in a given JITExtern instance.
470  Pipeline pipeline_;
471  ExternCFunction extern_c_function_;
472 
473 public:
474  EXPORT JITExtern(Pipeline pipeline);
475  EXPORT JITExtern(Func func);
476  EXPORT JITExtern(const ExternCFunction &extern_c_function);
477 
478  template <typename RT, typename... Args>
479  JITExtern(RT (*f)(Args... args)) : JITExtern(ExternCFunction(f)) {}
480 
481  const Pipeline &pipeline() const { return pipeline_; }
482  const ExternCFunction &extern_c_function() const { return extern_c_function_; }
483 };
484 
485 } // namespace Halide
486 
487 #endif
std::vector< InferredArgument > infer_arguments(Stmt body, const std::vector< Function > &outputs)
const Pipeline & pipeline() const
Definition: Pipeline.h:481
A class representing a Halide pipeline.
Definition: Pipeline.h:58
A reference-counted handle to a statement node.
Definition: Expr.h:356
void * address() const
Definition: Pipeline.h:462
A base class for passes over the IR which modify it (e.g.
Definition: IRMutator.h:124
A Realization is a vector of references to existing Buffer objects.
Definition: Tuple.h:69
A halide function.
Definition: Func.h:502
A struct specifying a collection of outputs.
Definition: Outputs.h:16
A struct representing the machine parameters to generate the auto-scheduled code for.
Definition: AutoSchedule.h:16
Defines Module, an IR container that fully describes a Halide program.
A struct representing a target machine and os to generate code for.
Definition: Target.h:21
Visible externally. Argument metadata and an argv wrapper are also generated.
Definition: Module.h:52
STL namespace.
A custom lowering pass.
Definition: Pipeline.h:49
Defines methods for manipulating and analyzing boolean expressions.
std::string print_loop_nest(const std::vector< Function > &output_funcs)
Emit some simple pseudocode that shows the structure of the loop nest specified by this pipeline&#39;s sc...
unsigned __INT8_TYPE__ uint8_t
Defines the structure that describes a Halide target.
Defines the method that does automatic scheduling of Funcs within a pipeline.
EXPORT Target get_jit_target_from_environment()
Return the target that Halide will use for jit-compilation.
Defines the struct representing lifetime and dependencies of a JIT compiled halide pipeline...
ExternSignature(RT(*f)(Args... args))
Definition: Pipeline.h:428
A halide module.
Definition: Module.h:83
JITExtern(RT(*f)(Args... args))
Definition: Pipeline.h:479
#define internal_assert(c)
Definition: Error.h:140
const std::vector< Type > & arg_types() const
Definition: Pipeline.h:443
char * dst
Definition: printer.h:30
ExternCFunction(RT(*f)(Args... args))
Definition: Pipeline.h:460
LinkageType
Type of linkage a function can have.
Definition: Module.h:50
Support classes for reference-counting via intrusive shared pointers.
ExternCFunction(void *address, const ExternSignature &signature)
Definition: Pipeline.h:456
static EXPORT MachineParams generic()
Default machine parameters for generic CPU architecture.
Internal::IRMutator2 * pass
Definition: Pipeline.h:50
const ExternCFunction & extern_c_function() const
Definition: Pipeline.h:482
void add_custom_lowering_pass(T *pass)
Add a custom pass to be used during lowering.
Definition: Pipeline.h:332
const ExternSignature & signature() const
Definition: Pipeline.h:463
EXPORT Target get_target_from_environment()
Return the target that Halide will use.
Types in the halide type system.
Definition: Type.h:285
void * malloc(size_t)
const Type & ret_type() const
Definition: Pipeline.h:434
ExternSignature(const Type &ret_type, bool is_void_return, const std::vector< Type > &arg_types)
Definition: Pipeline.h:420
#define EXPORT
Definition: Util.h:30
bool is_void_return() const
Definition: Pipeline.h:439
Type type_of()
Construct the halide equivalent of a C type.
Definition: Type.h:463
Defines Tuple - the front-end handle on small arrays of expressions.
void free(void *)
StmtOutputFormat
Used to determine if the output printed to file should be as a normal string or as an HTML file which...
Definition: Pipeline.h:34