Halide  17.0.2
Halide compiler and libraries
CodeGen_C.h
Go to the documentation of this file.
1 #ifndef HALIDE_CODEGEN_C_H
2 #define HALIDE_CODEGEN_C_H
3 
4 /** \file
5  *
6  * Defines an IRPrinter that emits C++ code equivalent to a halide stmt
7  */
8 
9 #include "IRPrinter.h"
10 #include "Scope.h"
11 #include "Target.h"
12 
13 namespace Halide {
14 
15 struct Argument;
16 class Module;
17 
18 namespace Internal {
19 
20 struct LoweredFunc;
21 
22 /** This class emits C++ code equivalent to a halide Stmt. It's
23  * mostly the same as an IRPrinter, but it's wrapped in a function
24  * definition, and some things are handled differently to be valid
25  * C++.
26  */
27 class CodeGen_C : public IRPrinter {
28 public:
29  enum OutputKind {
37  };
38 
39  /** Initialize a C code generator pointing at a particular output
40  * stream (e.g. a file, or std::cout) */
41  CodeGen_C(std::ostream &dest,
42  const Target &target,
44  const std::string &include_guard = "");
45  ~CodeGen_C() override;
46 
47  /** Emit the declarations contained in the module as C code. */
48  void compile(const Module &module);
49 
50  /** The target we're generating code for */
51  const Target &get_target() const {
52  return target;
53  }
54 
55  static void test();
56 
57 protected:
58  enum class IntegerSuffixStyle {
59  PlainC = 0,
60  OpenCL = 1,
61  HLSL = 2
62  };
63 
64  /** How to emit 64-bit integer constants */
66 
67  /** Emit a declaration. */
68  // @{
69  void compile(const LoweredFunc &func, const MetadataNameMap &metadata_name_map);
70  void compile(const Buffer<> &buffer);
71  // @}
72 
73  /** This is a hook that subclasses can use to transform a function body
74  * just before it is emitted -- e.g., to transform the IR to code that
75  * is easier to recognize and emit. The default implementation simply
76  * returns the input unchanged.
77  *
78  * This hook will always be called after the function declaration and
79  * opening brace is emitted, so in addition to (possibly) returning
80  * a modified Stmt, this function may also emit C++ code to the default
81  * stream if it wishes to add some prologue at the start of the function.
82  */
83  virtual Stmt preprocess_function_body(const Stmt &stmt);
84 
85  /** An ID for the most recently generated ssa variable */
86  std::string id;
87 
88  /** The target being generated for. */
90 
91  /** Controls whether this instance is generating declarations or
92  * definitions and whether the interface us extern "C" or C++. */
94 
95  /** A cache of generated values in scope */
96  std::map<std::string, std::string> cache;
97 
98  /** Emit an expression as an assignment, then return the id of the
99  * resulting var */
100  std::string print_expr(const Expr &);
101 
102  /** Like print_expr, but cast the Expr to the given Type */
103  std::string print_cast_expr(const Type &, const Expr &);
104 
105  /** Emit a statement */
106  void print_stmt(const Stmt &);
107 
108  void create_assertion(const std::string &id_cond, const Expr &message);
109  void create_assertion(const Expr &cond, const Expr &message);
110 
115  };
116 
117  /** Emit the C name for a halide type. If space_option is AppendSpace,
118  * and there should be a space between the type and the next token,
119  * one is appended. (This allows both "int foo" and "Foo *foo" to be
120  * formatted correctly. Otherwise the latter is "Foo * foo".)
121  */
122  virtual std::string print_type(Type, AppendSpaceIfNeeded space_option = DoNotAppendSpace);
123 
124  /** Emit a statement to reinterpret an expression as another type */
125  virtual std::string print_reinterpret(Type, const Expr &);
126 
127  /** Emit a version of a string that is a valid identifier in C (. is replaced with _) */
128  virtual std::string print_name(const std::string &);
129 
130  /** Add platform specific prologue */
131  virtual void add_platform_prologue();
132 
133  /** Add typedefs for vector types. Not needed for OpenCL, might
134  * use different syntax for other C-like languages. */
135  virtual void add_vector_typedefs(const std::set<Type> &vector_types);
136 
137  /** Bottleneck to allow customization of calls to generic Extern/PureExtern calls. */
138  virtual std::string print_extern_call(const Call *op);
139 
140  /** Convert a vector Expr into a series of scalar Exprs, then reassemble into vector of original type. */
141  std::string print_scalarized_expr(const Expr &e);
142 
143  /** Emit an SSA-style assignment, and set id to the freshly generated name. Return id. */
144  virtual std::string print_assignment(Type t, const std::string &rhs);
145 
146  /** Emit free for the heap allocation. **/
147  void print_heap_free(const std::string &alloc_name);
148 
149  /** Return true if only generating an interface, which may be extern "C" or C++ */
150  bool is_header() {
151  return output_kind == CHeader ||
154  }
155 
156  /** Return true if only generating an interface, which may be extern "C" or C++ */
157  bool is_extern_decl() {
158  return output_kind == CExternDecl ||
160  }
161 
162  /** Return true if only generating an interface, which may be extern "C" or C++ */
164  return is_header() || is_extern_decl();
165  }
166 
167  /** Return true if generating C++ linkage. */
169  return output_kind == CPlusPlusHeader ||
173  }
174 
175  /** Open a new C scope (i.e. throw in a brace, increase the indent) */
176  void open_scope();
177 
178  /** Close a C scope (i.e. throw in an end brace, decrease the indent) */
179  void close_scope(const std::string &comment);
180 
181  struct Allocation {
183  };
184 
185  /** Track the types of allocations to avoid unnecessary casts. */
187 
188  /** Track which allocations actually went on the heap. */
190 
191  /** True if there is a void * __user_context parameter in the arguments. */
193 
194  /** Track current calling convention scope. */
195  bool extern_c_open = false;
196 
197  /** True if at least one gpu-based for loop is used. */
199 
200  /** Track which handle types have been forward-declared already. */
201  std::set<const halide_handle_cplusplus_type *> forward_declared;
202 
203  /** If the Type is a handle type, emit a forward-declaration for it
204  * if we haven't already. */
205  void forward_declare_type_if_needed(const Type &t);
206 
208 
209  using IRPrinter::visit;
210 
211  void visit(const Variable *) override;
212  void visit(const IntImm *) override;
213  void visit(const UIntImm *) override;
214  void visit(const StringImm *) override;
215  void visit(const FloatImm *) override;
216  void visit(const Cast *) override;
217  void visit(const Reinterpret *) override;
218  void visit(const Add *) override;
219  void visit(const Sub *) override;
220  void visit(const Mul *) override;
221  void visit(const Div *) override;
222  void visit(const Mod *) override;
223  void visit(const Max *) override;
224  void visit(const Min *) override;
225  void visit(const EQ *) override;
226  void visit(const NE *) override;
227  void visit(const LT *) override;
228  void visit(const LE *) override;
229  void visit(const GT *) override;
230  void visit(const GE *) override;
231  void visit(const And *) override;
232  void visit(const Or *) override;
233  void visit(const Not *) override;
234  void visit(const Call *) override;
235  void visit(const Select *) override;
236  void visit(const Load *) override;
237  void visit(const Store *) override;
238  void visit(const Let *) override;
239  void visit(const LetStmt *) override;
240  void visit(const AssertStmt *) override;
241  void visit(const ProducerConsumer *) override;
242  void visit(const For *) override;
243  void visit(const Ramp *) override;
244  void visit(const Broadcast *) override;
245  void visit(const Provide *) override;
246  void visit(const Allocate *) override;
247  void visit(const Free *) override;
248  void visit(const Realize *) override;
249  void visit(const IfThenElse *) override;
250  void visit(const Evaluate *) override;
251  void visit(const Shuffle *) override;
252  void visit(const Prefetch *) override;
253  void visit(const Fork *) override;
254  void visit(const Acquire *) override;
255  void visit(const Atomic *) override;
256  void visit(const VectorReduce *) override;
257 
258  void visit_binop(Type t, const Expr &a, const Expr &b, const char *op);
259  void visit_relop(Type t, const Expr &a, const Expr &b, const char *scalar_op, const char *vector_op);
260 
261  template<typename T>
262  static std::string with_sep(const std::vector<T> &v, const std::string &sep) {
263  std::ostringstream o;
264  for (size_t i = 0; i < v.size(); ++i) {
265  if (i > 0) {
266  o << sep;
267  }
268  o << v[i];
269  }
270  return o.str();
271  }
272 
273  template<typename T>
274  static std::string with_commas(const std::vector<T> &v) {
275  return with_sep<T>(v, ", ");
276  }
277 
278  /** Are we inside an atomic node that uses mutex locks?
279  This is used for detecting deadlocks from nested atomics. */
281 
282  /** Emit atomic store instructions? */
283  bool emit_atomic_stores = false;
284 
285  /** true if add_vector_typedefs() has been called. */
286  bool using_vector_typedefs = false;
287 
288  /** Some architectures have private memory for the call stack; this
289  * means a thread cannot hand pointers to stack memory to another
290  * thread. Returning true here flag forces heap allocation of
291  * things that might be shared, such as closures and any buffer
292  * that may be used in a parallel context. */
293  virtual bool is_stack_private_to_thread() const;
294 
295  void emit_argv_wrapper(const std::string &function_name,
296  const std::vector<LoweredArgument> &args);
297  void emit_metadata_getter(const std::string &function_name,
298  const std::vector<LoweredArgument> &args,
299  const MetadataNameMap &metadata_name_map);
300  void emit_constexpr_function_info(const std::string &function_name,
301  const std::vector<LoweredArgument> &args,
302  const MetadataNameMap &metadata_name_map);
303  void emit_halide_free_helper(const std::string &alloc_name, const std::string &free_function);
304 };
305 
306 } // namespace Internal
307 } // namespace Halide
308 
309 #endif
Unsigned integer constants.
Definition: Expr.h:227
Scope< Allocation > allocations
Track the types of allocations to avoid unnecessary casts.
Definition: CodeGen_C.h:186
The actual IR nodes begin here.
Definition: IR.h:30
A named variable.
Definition: IR.h:758
static std::string with_commas(const std::vector< T > &v)
Definition: CodeGen_C.h:274
void open_scope()
Open a new C scope (i.e.
virtual std::string print_assignment(Type t, const std::string &rhs)
Emit an SSA-style assignment, and set id to the freshly generated name.
Expr scalarize_vector_reduce(const VectorReduce *op)
bool is_header_or_extern_decl()
Return true if only generating an interface, which may be extern "C" or C++.
Definition: CodeGen_C.h:163
A fragment of Halide syntax.
Definition: Expr.h:258
bool is_c_plus_plus_interface()
Return true if generating C++ linkage.
Definition: CodeGen_C.h:168
Integer constants.
Definition: Expr.h:218
Is the first expression greater than the second.
Definition: IR.h:157
A reference-counted handle to a statement node.
Definition: Expr.h:419
Load a value from a named symbol if predicate is true.
Definition: IR.h:217
The difference of two expressions.
Definition: IR.h:65
A vector with &#39;lanes&#39; elements, in which every element is &#39;value&#39;.
Definition: IR.h:259
Logical and - are both expressions true.
Definition: IR.h:175
void close_scope(const std::string &comment)
Close a C scope (i.e.
virtual std::string print_type(Type, AppendSpaceIfNeeded space_option=DoNotAppendSpace)
Emit the C name for a halide type.
Logical not - true if the expression false.
Definition: IR.h:193
Horizontally reduce a vector to a scalar or narrower vector using the given commutative and associati...
Definition: IR.h:966
A struct representing a target machine and os to generate code for.
Definition: Target.h:19
Is the first expression less than the second.
Definition: IR.h:139
The product of two expressions.
Definition: IR.h:74
This class emits C++ code equivalent to a halide Stmt.
Definition: CodeGen_C.h:27
Lock all the Store nodes in the body statement.
Definition: IR.h:948
void emit_argv_wrapper(const std::string &function_name, const std::vector< LoweredArgument > &args)
Floating point constants.
Definition: Expr.h:236
A ternary operator.
Definition: IR.h:204
std::string print_cast_expr(const Type &, const Expr &)
Like print_expr, but cast the Expr to the given Type.
The sum of two expressions.
Definition: IR.h:56
This header file defines operators that let you dump a Halide expression, statement, or type directly into an output stream in a human readable form.
void visit_relop(Type t, const Expr &a, const Expr &b, const char *scalar_op, const char *vector_op)
A linear ramp vector node.
Definition: IR.h:247
An if-then-else block.
Definition: IR.h:466
void emit_metadata_getter(const std::string &function_name, const std::vector< LoweredArgument > &args, const MetadataNameMap &metadata_name_map)
Allocate a multi-dimensional buffer of the given type and size.
Definition: IR.h:427
This file defines the class FunctionDAG, which is our representation of a Halide pipeline, and contains methods to using Halide&#39;s bounds tools to query properties of it.
bool uses_gpu_for_loops
True if at least one gpu-based for loop is used.
Definition: CodeGen_C.h:198
An IRVisitor that emits IR to the given output stream in a human readable form.
Definition: IRPrinter.h:105
Defines the structure that describes a Halide target.
Store a &#39;value&#39; to the buffer called &#39;name&#39; at a given &#39;index&#39; if &#39;predicate&#39; is true.
Definition: IR.h:333
bool extern_c_open
Track current calling convention scope.
Definition: CodeGen_C.h:195
Allocate a scratch area called with the given name, type, and size.
Definition: IR.h:371
CodeGen_C(std::ostream &dest, const Target &target, OutputKind output_kind=CImplementation, const std::string &include_guard="")
Initialize a C code generator pointing at a particular output stream (e.g.
void print_stmt(const Stmt &)
Emit a statement.
virtual bool is_stack_private_to_thread() const
Some architectures have private memory for the call stack; this means a thread cannot hand pointers t...
Is the first expression greater than or equal to the second.
Definition: IR.h:166
bool inside_atomic_mutex_node
Are we inside an atomic node that uses mutex locks? This is used for detecting deadlocks from nested ...
Definition: CodeGen_C.h:280
A for loop.
Definition: IR.h:805
A common pattern when traversing Halide IR is that you need to keep track of stuff when you find a Le...
void visit(const IntImm *) override
void visit(const Variable *) override
This defines the value of a function at a multi-dimensional location.
Definition: IR.h:354
Represent a multi-dimensional region of a Func or an ImageParam that needs to be prefetched.
Definition: IR.h:910
The ratio of two expressions.
Definition: IR.h:83
std::map< std::string, std::string > MetadataNameMap
Definition: Module.h:138
A halide module.
Definition: Module.h:142
A function call.
Definition: IR.h:490
Definition of a lowered function.
Definition: Module.h:101
static std::string with_sep(const std::vector< T > &v, const std::string &sep)
Definition: CodeGen_C.h:262
std::string print_expr(const Expr &)
Emit an expression as an assignment, then return the id of the resulting var.
virtual std::string print_reinterpret(Type, const Expr &)
Emit a statement to reinterpret an expression as another type.
Is the first expression less than or equal to the second.
Definition: IR.h:148
Is the first expression not equal to the second.
Definition: IR.h:130
bool have_user_context
True if there is a void * __user_context parameter in the arguments.
Definition: CodeGen_C.h:192
const Target & get_target() const
The target we&#39;re generating code for.
Definition: CodeGen_C.h:51
virtual void add_vector_typedefs(const std::set< Type > &vector_types)
Add typedefs for vector types.
void create_assertion(const std::string &id_cond, const Expr &message)
If the &#39;condition&#39; is false, then evaluate and return the message, which should be a call to an error...
Definition: IR.h:294
void visit_binop(Type t, const Expr &a, const Expr &b, const char *op)
bool using_vector_typedefs
true if add_vector_typedefs() has been called.
Definition: CodeGen_C.h:286
Not visible externally, similar to &#39;static&#39; linkage in C.
Is the first expression equal to the second.
Definition: IR.h:121
The greater of two values.
Definition: IR.h:112
A pair of statements executed concurrently.
Definition: IR.h:457
void set_name_mangling_mode(NameMangling mode)
void print_heap_free(const std::string &alloc_name)
Emit free for the heap allocation.
Defines the Scope class, which is used for keeping track of names in a scope while traversing IR...
A let expression, like you might find in a functional language.
Definition: IR.h:271
Free the resources associated with the given buffer.
Definition: IR.h:413
std::string id
An ID for the most recently generated ssa variable.
Definition: CodeGen_C.h:86
bool emit_atomic_stores
Emit atomic store instructions?
Definition: CodeGen_C.h:283
virtual std::string print_extern_call(const Call *op)
Bottleneck to allow customization of calls to generic Extern/PureExtern calls.
Types in the halide type system.
Definition: Type.h:276
NameMangling
An enum to specify calling convention for extern stages.
Definition: Function.h:25
void forward_declare_type_if_needed(const Type &t)
If the Type is a handle type, emit a forward-declaration for it if we haven&#39;t already.
std::string print_scalarized_expr(const Expr &e)
Convert a vector Expr into a series of scalar Exprs, then reassemble into vector of original type...
virtual void add_platform_prologue()
Add platform specific prologue.
The lesser of two values.
Definition: IR.h:103
virtual std::string print_name(const std::string &)
Emit a version of a string that is a valid identifier in C (.
virtual Stmt preprocess_function_body(const Stmt &stmt)
This is a hook that subclasses can use to transform a function body just before it is emitted – e...
The remainder of a / b.
Definition: IR.h:94
Reinterpret value as another type, without affecting any of the bits (on little-endian systems)...
Definition: IR.h:47
std::set< const halide_handle_cplusplus_type * > forward_declared
Track which handle types have been forward-declared already.
Definition: CodeGen_C.h:201
String constants.
Definition: Expr.h:245
The statement form of a let node.
Definition: IR.h:282
bool is_header()
Return true if only generating an interface, which may be extern "C" or C++.
Definition: CodeGen_C.h:150
Target target
The target being generated for.
Definition: CodeGen_C.h:89
Logical or - is at least one of the expression true.
Definition: IR.h:184
This node is a helpful annotation to do with permissions.
Definition: IR.h:315
Scope heap_allocations
Track which allocations actually went on the heap.
Definition: CodeGen_C.h:189
void emit_halide_free_helper(const std::string &alloc_name, const std::string &free_function)
IntegerSuffixStyle integer_suffix_style
How to emit 64-bit integer constants.
Definition: CodeGen_C.h:65
void emit_constexpr_function_info(const std::string &function_name, const std::vector< LoweredArgument > &args, const MetadataNameMap &metadata_name_map)
Evaluate and discard an expression, presumably because it has some side-effect.
Definition: IR.h:476
bool is_extern_decl()
Return true if only generating an interface, which may be extern "C" or C++.
Definition: CodeGen_C.h:157
void compile(const Module &module)
Emit the declarations contained in the module as C code.
OutputKind output_kind
Controls whether this instance is generating declarations or definitions and whether the interface us...
Definition: CodeGen_C.h:93
std::map< std::string, std::string > cache
A cache of generated values in scope.
Definition: CodeGen_C.h:96
Construct a new vector by taking elements from another sequence of vectors.
Definition: IR.h:841