Halide
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 "Module.h"
11 #include "Scope.h"
12 
13 namespace Halide {
14 
15 struct Argument;
16 
17 namespace Internal {
18 
19 /** This class emits C++ code equivalent to a halide Stmt. It's
20  * mostly the same as an IRPrinter, but it's wrapped in a function
21  * definition, and some things are handled differently to be valid
22  * C++.
23  */
24 class CodeGen_C : public IRPrinter {
25 public:
26  enum OutputKind {
33  };
34 
35  /** Initialize a C code generator pointing at a particular output
36  * stream (e.g. a file, or std::cout) */
37  CodeGen_C(std::ostream &dest,
38  Target target,
40  const std::string &include_guard = "");
41  ~CodeGen_C() override;
42 
43  /** Emit the declarations contained in the module as C code. */
44  void compile(const Module &module);
45 
46  /** The target we're generating code for */
47  const Target &get_target() const {
48  return target;
49  }
50 
51  static void test();
52 
53  /** Add common macros to be shared across all backends */
54  void add_common_macros(std::ostream &dest);
55 
56 protected:
57  /** Emit a declaration. */
58  // @{
59  virtual void compile(const LoweredFunc &func);
60  virtual void compile(const Buffer<> &buffer);
61  // @}
62 
63  /** An ID for the most recently generated ssa variable */
64  std::string id;
65 
66  /** The target being generated for. */
68 
69  /** Controls whether this instance is generating declarations or
70  * definitions and whether the interface us extern "C" or C++. */
72 
73  /** A cache of generated values in scope */
74  std::map<std::string, std::string> cache;
75 
76  /** Emit an expression as an assignment, then return the id of the
77  * resulting var */
78  std::string print_expr(const Expr &);
79 
80  /** Like print_expr, but cast the Expr to the given Type */
81  std::string print_cast_expr(const Type &, const Expr &);
82 
83  /** Emit a statement */
84  void print_stmt(const Stmt &);
85 
86  void create_assertion(const std::string &id_cond, const Expr &message);
87  void create_assertion(const Expr &cond, const Expr &message);
88 
92  };
93 
94  /** Emit the C name for a halide type. If space_option is AppendSpace,
95  * and there should be a space between the type and the next token,
96  * one is appended. (This allows both "int foo" and "Foo *foo" to be
97  * formatted correctly. Otherwise the latter is "Foo * foo".)
98  */
99  virtual std::string print_type(Type, AppendSpaceIfNeeded space_option = DoNotAppendSpace);
100 
101  /** Emit a statement to reinterpret an expression as another type */
102  virtual std::string print_reinterpret(Type, const Expr &);
103 
104  /** Emit a version of a string that is a valid identifier in C (. is replaced with _) */
105  virtual std::string print_name(const std::string &);
106 
107  /** Add typedefs for vector types. Not needed for OpenCL, might
108  * use different syntax for other C-like languages. */
109  virtual void add_vector_typedefs(const std::set<Type> &vector_types);
110 
111  /** Bottleneck to allow customization of calls to generic Extern/PureExtern calls. */
112  virtual std::string print_extern_call(const Call *op);
113 
114  /** Convert a vector Expr into a series of scalar Exprs, then reassemble into vector of original type. */
115  std::string print_scalarized_expr(const Expr &e);
116 
117  /** Emit an SSA-style assignment, and set id to the freshly generated name. Return id. */
118  virtual std::string print_assignment(Type t, const std::string &rhs);
119 
120  /** Emit free for the heap allocation. **/
121  void print_heap_free(const std::string &alloc_name);
122 
123  /** Return true if only generating an interface, which may be extern "C" or C++ */
124  bool is_header() {
125  return output_kind == CHeader ||
127  }
128 
129  /** Return true if only generating an interface, which may be extern "C" or C++ */
130  bool is_extern_decl() {
131  return output_kind == CExternDecl ||
133  }
134 
135  /** Return true if only generating an interface, which may be extern "C" or C++ */
137  return is_header() || is_extern_decl();
138  }
139 
140  /** Return true if generating C++ linkage. */
142  return output_kind == CPlusPlusHeader ||
145  }
146 
147  /** Open a new C scope (i.e. throw in a brace, increase the indent) */
148  void open_scope();
149 
150  /** Close a C scope (i.e. throw in an end brace, decrease the indent) */
151  void close_scope(const std::string &comment);
152 
153  struct Allocation {
155  };
156 
157  /** Track the types of allocations to avoid unnecessary casts. */
159 
160  /** Track which allocations actually went on the heap. */
162 
163  /** True if there is a void * __user_context parameter in the arguments. */
165 
166  /** Track current calling convention scope. */
168 
169  /** True if at least one gpu-based for loop is used. */
171 
172  /** Track which handle types have been forward-declared already. */
173  std::set<const halide_handle_cplusplus_type *> forward_declared;
174 
175  /** If the Type is a handle type, emit a forward-declaration for it
176  * if we haven't already. */
177  void forward_declare_type_if_needed(const Type &t);
178 
180 
181  using IRPrinter::visit;
182 
183  void visit(const Variable *) override;
184  void visit(const IntImm *) override;
185  void visit(const UIntImm *) override;
186  void visit(const StringImm *) override;
187  void visit(const FloatImm *) override;
188  void visit(const Cast *) override;
189  void visit(const Add *) override;
190  void visit(const Sub *) override;
191  void visit(const Mul *) override;
192  void visit(const Div *) override;
193  void visit(const Mod *) override;
194  void visit(const Max *) override;
195  void visit(const Min *) override;
196  void visit(const EQ *) override;
197  void visit(const NE *) override;
198  void visit(const LT *) override;
199  void visit(const LE *) override;
200  void visit(const GT *) override;
201  void visit(const GE *) override;
202  void visit(const And *) override;
203  void visit(const Or *) override;
204  void visit(const Not *) override;
205  void visit(const Call *) override;
206  void visit(const Select *) override;
207  void visit(const Load *) override;
208  void visit(const Store *) override;
209  void visit(const Let *) override;
210  void visit(const LetStmt *) override;
211  void visit(const AssertStmt *) override;
212  void visit(const ProducerConsumer *) override;
213  void visit(const For *) override;
214  void visit(const Ramp *) override;
215  void visit(const Broadcast *) override;
216  void visit(const Provide *) override;
217  void visit(const Allocate *) override;
218  void visit(const Free *) override;
219  void visit(const Realize *) override;
220  void visit(const IfThenElse *) override;
221  void visit(const Evaluate *) override;
222  void visit(const Shuffle *) override;
223  void visit(const Prefetch *) override;
224  void visit(const Fork *) override;
225  void visit(const Acquire *) override;
226  void visit(const Atomic *) override;
227 
228  void visit_binop(Type t, const Expr &a, const Expr &b, const char *op);
229 
230  template<typename T>
231  static std::string with_sep(const std::vector<T> &v, const std::string &sep) {
232  std::ostringstream o;
233  for (size_t i = 0; i < v.size(); ++i) {
234  if (i > 0) {
235  o << sep;
236  }
237  o << v[i];
238  }
239  return o.str();
240  }
241 
242  template<typename T>
243  static std::string with_commas(const std::vector<T> &v) {
244  return with_sep<T>(v, ", ");
245  }
246 
247  /** Are we inside an atomic node that uses mutex locks?
248  This is used for detecting deadlocks from nested atomics. */
250 
251  /** Emit atomic store instructions? */
253 };
254 
255 } // namespace Internal
256 } // namespace Halide
257 
258 #endif
Halide::Internal::CodeGen_C::uses_gpu_for_loops
bool uses_gpu_for_loops
True if at least one gpu-based for loop is used.
Definition: CodeGen_C.h:170
Halide::Internal::Acquire
Definition: IR.h:717
Halide::Internal::CodeGen_C::add_common_macros
void add_common_macros(std::ostream &dest)
Add common macros to be shared across all backends.
Halide::Internal::CodeGen_C::target
Target target
The target being generated for.
Definition: CodeGen_C.h:67
Halide::Internal::Allocate
Allocate a scratch area called with the given name, type, and size.
Definition: IR.h:352
Halide::Internal::CodeGen_C::emit_atomic_stores
bool emit_atomic_stores
Emit atomic store instructions?
Definition: CodeGen_C.h:252
Halide::Internal::Add
The sum of two expressions.
Definition: IR.h:38
Scope.h
Halide::Internal::CodeGen_C::close_scope
void close_scope(const std::string &comment)
Close a C scope (i.e.
Halide::Internal::CodeGen_C::print_type
virtual std::string print_type(Type, AppendSpaceIfNeeded space_option=DoNotAppendSpace)
Emit the C name for a halide type.
Halide::Internal::CodeGen_C::compile
void compile(const Module &module)
Emit the declarations contained in the module as C code.
Halide::Internal::CodeGen_C::visit
void visit(const Variable *) override
Halide::Internal::GE
Is the first expression greater than or equal to the second.
Definition: IR.h:148
Halide::Internal::For
A for loop.
Definition: IR.h:698
IRPrinter.h
Halide::Internal::CodeGen_C::print_name
virtual std::string print_name(const std::string &)
Emit a version of a string that is a valid identifier in C (.
Halide::Internal::CodeGen_C::with_sep
static std::string with_sep(const std::vector< T > &v, const std::string &sep)
Definition: CodeGen_C.h:231
Halide::Internal::FloatImm
Floating point constants.
Definition: Expr.h:234
Halide::Internal::IRPrinter
An IRVisitor that emits IR to the given output stream in a human readable form.
Definition: IRPrinter.h:98
Halide::Internal::Broadcast
A vector with 'lanes' elements, in which every element is 'value'.
Definition: IR.h:241
Halide::Internal::Div
The ratio of two expressions.
Definition: IR.h:65
Halide::Internal::CodeGen_C::get_target
const Target & get_target() const
The target we're generating code for.
Definition: CodeGen_C.h:47
Halide::Internal::IntImm
Integer constants.
Definition: Expr.h:216
Halide::Internal::LetStmt
The statement form of a let node.
Definition: IR.h:264
Halide::Internal::CodeGen_C::CPlusPlusHeader
@ CPlusPlusHeader
Definition: CodeGen_C.h:28
Halide::Internal::CodeGen_C::create_assertion
void create_assertion(const std::string &id_cond, const Expr &message)
Halide::Internal::Scope
A common pattern when traversing Halide IR is that you need to keep track of stuff when you find a Le...
Definition: ModulusRemainder.h:17
Halide::Internal::Cast
The actual IR nodes begin here.
Definition: IR.h:29
Halide::Internal::LE
Is the first expression less than or equal to the second.
Definition: IR.h:130
Halide::Internal::NE
Is the first expression not equal to the second.
Definition: IR.h:112
Halide::Internal::Fork
A pair of statements executed concurrently.
Definition: IR.h:431
Halide::Internal::CodeGen_C::output_kind
OutputKind output_kind
Controls whether this instance is generating declarations or definitions and whether the interface us...
Definition: CodeGen_C.h:71
Halide::Internal::CodeGen_C::CPlusPlusImplementation
@ CPlusPlusImplementation
Definition: CodeGen_C.h:30
Halide::Internal::CodeGen_C::CodeGen_C
CodeGen_C(std::ostream &dest, Target target, OutputKind output_kind=CImplementation, const std::string &include_guard="")
Initialize a C code generator pointing at a particular output stream (e.g.
Halide::Internal::Stmt
A reference-counted handle to a statement node.
Definition: Expr.h:409
Halide::Internal::CodeGen_C
This class emits C++ code equivalent to a halide Stmt.
Definition: CodeGen_C.h:24
Halide::Internal::CodeGen_C::with_commas
static std::string with_commas(const std::vector< T > &v)
Definition: CodeGen_C.h:243
Halide::Internal::CodeGen_C::print_scalarized_expr
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.
Halide::Module
A halide module.
Definition: Module.h:136
Halide::Type
Types in the halide type system.
Definition: Type.h:269
Halide::Internal::CodeGen_C::open_scope
void open_scope()
Open a new C scope (i.e.
Halide::Internal::Load
Load a value from a named symbol if predicate is true.
Definition: IR.h:199
Halide::Internal::Free
Free the resources associated with the given buffer.
Definition: IR.h:388
Halide::Internal::Realize
Allocate a multi-dimensional buffer of the given type and size.
Definition: IR.h:402
Halide
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
Definition: AddAtomicMutex.h:21
Halide::Internal::CodeGen_C::print_heap_free
void print_heap_free(const std::string &alloc_name)
Emit free for the heap allocation.
Halide::Internal::Or
Logical or - is at least one of the expression true.
Definition: IR.h:166
Halide::Internal::EQ
Is the first expression equal to the second.
Definition: IR.h:103
Halide::Internal::Provide
This defines the value of a function at a multi-dimensional location.
Definition: IR.h:336
Halide::Internal::CodeGen_C::add_vector_typedefs
virtual void add_vector_typedefs(const std::set< Type > &vector_types)
Add typedefs for vector types.
Halide::Internal::CodeGen_C::AppendSpaceIfNeeded
AppendSpaceIfNeeded
Definition: CodeGen_C.h:89
Halide::LinkageType::Internal
@ Internal
Not visible externally, similar to 'static' linkage in C.
Halide::Internal::Max
The greater of two values.
Definition: IR.h:94
Halide::Internal::CodeGen_C::AppendSpace
@ AppendSpace
Definition: CodeGen_C.h:91
Halide::Internal::CodeGen_C::print_extern_call
virtual std::string print_extern_call(const Call *op)
Bottleneck to allow customization of calls to generic Extern/PureExtern calls.
Halide::Internal::CodeGen_C::heap_allocations
Scope heap_allocations
Track which allocations actually went on the heap.
Definition: CodeGen_C.h:161
Halide::Buffer<>
Halide::Internal::Let
A let expression, like you might find in a functional language.
Definition: IR.h:253
Halide::Internal::CodeGen_C::is_extern_decl
bool is_extern_decl()
Return true if only generating an interface, which may be extern "C" or C++.
Definition: CodeGen_C.h:130
Halide::Internal::CodeGen_C::cache
std::map< std::string, std::string > cache
A cache of generated values in scope.
Definition: CodeGen_C.h:74
Halide::Internal::Ramp
A linear ramp vector node.
Definition: IR.h:229
Halide::Internal::IRPrinter::visit
void visit(const IntImm *) override
Halide::Internal::CodeGen_C::Allocation
Definition: CodeGen_C.h:153
Halide::Internal::CodeGen_C::print_assignment
virtual std::string print_assignment(Type t, const std::string &rhs)
Emit an SSA-style assignment, and set id to the freshly generated name.
Halide::Internal::Evaluate
Evaluate and discard an expression, presumably because it has some side-effect.
Definition: IR.h:450
Halide::Internal::Store
Store a 'value' to the buffer called 'name' at a given 'index' if 'predicate' is true.
Definition: IR.h:315
Halide::Internal::CodeGen_C::test
static void test()
Halide::Internal::cond
Definition: Generator.h:379
Halide::Internal::LoweredFunc
Definition of a lowered function.
Definition: Module.h:97
Halide::Internal::Variable
A named variable.
Definition: IR.h:651
Halide::Internal::CodeGen_C::id
std::string id
An ID for the most recently generated ssa variable.
Definition: CodeGen_C.h:64
Halide::NameMangling
NameMangling
An enum to specify calling convention for extern stages.
Definition: Function.h:24
Halide::Internal::Min
The lesser of two values.
Definition: IR.h:85
Halide::Internal::ProducerConsumer
This node is a helpful annotation to do with permissions.
Definition: IR.h:297
Halide::Internal::Mod
The remainder of a / b.
Definition: IR.h:76
Halide::Internal::AssertStmt
If the 'condition' is false, then evaluate and return the message, which should be a call to an error...
Definition: IR.h:276
Halide::Internal::CodeGen_C::inside_atomic_mutex_node
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:249
Halide::Internal::CodeGen_C::Allocation::type
Type type
Definition: CodeGen_C.h:154
Halide::Internal::CodeGen_C::OutputKind
OutputKind
Definition: CodeGen_C.h:26
Halide::Internal::CodeGen_C::CHeader
@ CHeader
Definition: CodeGen_C.h:27
Halide::Internal::Call
A function call.
Definition: IR.h:464
Halide::Internal::CodeGen_C::is_header_or_extern_decl
bool is_header_or_extern_decl()
Return true if only generating an interface, which may be extern "C" or C++.
Definition: CodeGen_C.h:136
Halide::Internal::CodeGen_C::set_name_mangling_mode
void set_name_mangling_mode(NameMangling mode)
Halide::Internal::CodeGen_C::is_header
bool is_header()
Return true if only generating an interface, which may be extern "C" or C++.
Definition: CodeGen_C.h:124
Halide::Internal::Select
A ternary operator.
Definition: IR.h:186
Halide::Internal::CodeGen_C::CImplementation
@ CImplementation
Definition: CodeGen_C.h:29
Halide::Expr
A fragment of Halide syntax.
Definition: Expr.h:256
Halide::Internal::CodeGen_C::extern_c_open
bool extern_c_open
Track current calling convention scope.
Definition: CodeGen_C.h:167
Halide::Internal::Prefetch
Represent a multi-dimensional region of a Func or an ImageParam that needs to be prefetched.
Definition: IR.h:786
Halide::Internal::CodeGen_C::visit_binop
void visit_binop(Type t, const Expr &a, const Expr &b, const char *op)
Halide::Internal::GT
Is the first expression greater than the second.
Definition: IR.h:139
Halide::Internal::CodeGen_C::print_stmt
void print_stmt(const Stmt &)
Emit a statement.
Halide::Internal::Atomic
Lock all the Store nodes in the body statement.
Definition: IR.h:809
Halide::Internal::Shuffle
Construct a new vector by taking elements from another sequence of vectors.
Definition: IR.h:729
Module.h
Halide::Internal::UIntImm
Unsigned integer constants.
Definition: Expr.h:225
Halide::Internal::CodeGen_C::forward_declare_type_if_needed
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't already.
Halide::Internal::CodeGen_C::allocations
Scope< Allocation > allocations
Track the types of allocations to avoid unnecessary casts.
Definition: CodeGen_C.h:158
Halide::Internal::CodeGen_C::CExternDecl
@ CExternDecl
Definition: CodeGen_C.h:31
Halide::Internal::IfThenElse
An if-then-else block.
Definition: IR.h:440
Halide::Internal::Sub
The difference of two expressions.
Definition: IR.h:47
Halide::Internal::CodeGen_C::DoNotAppendSpace
@ DoNotAppendSpace
Definition: CodeGen_C.h:90
Halide::Target
A struct representing a target machine and os to generate code for.
Definition: Target.h:19
Halide::Internal::And
Logical and - are both expressions true.
Definition: IR.h:157
Halide::Internal::CodeGen_C::CPlusPlusExternDecl
@ CPlusPlusExternDecl
Definition: CodeGen_C.h:32
Halide::Internal::CodeGen_C::print_cast_expr
std::string print_cast_expr(const Type &, const Expr &)
Like print_expr, but cast the Expr to the given Type.
Halide::Internal::CodeGen_C::is_c_plus_plus_interface
bool is_c_plus_plus_interface()
Return true if generating C++ linkage.
Definition: CodeGen_C.h:141
Halide::Internal::StringImm
String constants.
Definition: Expr.h:243
Halide::Internal::Not
Logical not - true if the expression false.
Definition: IR.h:175
Halide::Internal::LT
Is the first expression less than the second.
Definition: IR.h:121
Halide::Internal::CodeGen_C::forward_declared
std::set< const halide_handle_cplusplus_type * > forward_declared
Track which handle types have been forward-declared already.
Definition: CodeGen_C.h:173
Halide::Internal::Mul
The product of two expressions.
Definition: IR.h:56
Halide::Internal::CodeGen_C::~CodeGen_C
~CodeGen_C() override
Halide::Internal::CodeGen_C::print_expr
std::string print_expr(const Expr &)
Emit an expression as an assignment, then return the id of the resulting var.
Halide::Internal::CodeGen_C::print_reinterpret
virtual std::string print_reinterpret(Type, const Expr &)
Emit a statement to reinterpret an expression as another type.
Halide::Internal::CodeGen_C::have_user_context
bool have_user_context
True if there is a void * __user_context parameter in the arguments.
Definition: CodeGen_C.h:164