1 #ifndef HALIDE_MODULE_H
2 #define HALIDE_MODULE_H
3 
4 /** \file
5  *
6  * Defines Module, an IR container that fully describes a Halide program.
7  */
8 
9 #include <functional>
10 #include <map>
11 #include <memory>
12 #include <set>
13 #include <string>
14 
15 #include "Argument.h"
16 #include "Expr.h"
17 #include "ExternalCode.h"
18 #include "Function.h"  // for NameMangling
19 #include "ModulusRemainder.h"
20 #include "Target.h"
21 
22 namespace Halide {
23 
24 template<typename T>
25 class Buffer;
26 
27 /** Enums specifying various kinds of outputs that can be produced from a Halide Pipeline. */
28 enum class Output {
29     assembly,
30     bitcode,
31     c_header,
32     c_source,
33     compiler_log,
34     cpp_stub,
35     featurization,
36     llvm_assembly,
37     object,
38     python_extension,
39     pytorch_wrapper,
40     registration,
41     schedule,
42     static_library,
43     stmt,
44     stmt_html,
45 };
46 
47 /** Type of linkage a function in a lowered Halide module can have.
48     Also controls whether auxiliary functions and metadata are generated. */
49 enum class LinkageType {
50     External,              ///< Visible externally.
51     ExternalPlusMetadata,  ///< Visible externally. Argument metadata and an argv wrapper are also generated.
52     Internal,              ///< Not visible externally, similar to 'static' linkage in C.
53 };
54 
55 namespace Internal {
56 
57 struct OutputInfo {
58     std::string name, extension;
59 
60     // `is_multi` indicates how these outputs are generated
61     // when using the compile_to_multitarget_xxx() APIs (or via the
62     // Generator command-line mode):
63     //
64     // - If `is_multi` is true, then a separate file of this Output type is
65     //   generated for each target in the multitarget (e.g. object files,
66     //   assembly files, etc). Each of the files will have a suffix appended
67     //   that is based on the specific subtarget.
68     //
69     // - If `is_multi` is false, then only one file of this Output type
70     //   regardless of how many targets are in the multitarget. No additional
71     //   suffix will be appended to the filename.
72     //
73     bool is_multi{false};
74 };
75 std::map<Output, const OutputInfo> get_output_info(const Target &target);
76 
77 /** Definition of an argument to a LoweredFunc. This is similar to
78  * Argument, except it enables passing extra information useful to
79  * some targets to LoweredFunc. */
80 struct LoweredArgument : public Argument {
81     /** For scalar arguments, the modulus and remainder of this
82      * argument. */
83     ModulusRemainder alignment;
84 
85     LoweredArgument() = default;
LoweredArgumentLoweredArgument86     explicit LoweredArgument(const Argument &arg)
87         : Argument(arg) {
88     }
LoweredArgumentLoweredArgument89     LoweredArgument(const std::string &_name, Kind _kind, const Type &_type, uint8_t _dimensions, const ArgumentEstimates &argument_estimates)
90         : Argument(_name, _kind, _type, _dimensions, argument_estimates) {
91     }
92 };
93 
94 /** Definition of a lowered function. This object provides a concrete
95  * mapping between parameters used in the function body and their
96  * declarations in the argument list. */
97 struct LoweredFunc {
98     std::string name;
99 
100     /** Arguments referred to in the body of this function. */
101     std::vector<LoweredArgument> args;
102 
103     /** Body of this function. */
104     Stmt body;
105 
106     /** The linkage of this function. */
107     LinkageType linkage;
108 
109     /** The name-mangling choice for the function. Defaults to using
110      * the Target. */
111     NameMangling name_mangling;
112 
113     LoweredFunc(const std::string &name,
114                 const std::vector<LoweredArgument> &args,
115                 Stmt body,
116                 LinkageType linkage,
117                 NameMangling mangling = NameMangling::Default);
118     LoweredFunc(const std::string &name,
119                 const std::vector<Argument> &args,
120                 Stmt body,
121                 LinkageType linkage,
122                 NameMangling mangling = NameMangling::Default);
123 };
124 
125 }  // namespace Internal
126 
127 namespace Internal {
128 struct ModuleContents;
129 class CompilerLogger;
130 }  // namespace Internal
131 
132 struct AutoSchedulerResults;
133 
134 /** A halide module. This represents IR containing lowered function
135  * definitions and buffers. */
136 class Module {
137     Internal::IntrusivePtr<Internal::ModuleContents> contents;
138 
139 public:
140     Module(const std::string &name, const Target &target);
141 
142     /** Get the target this module has been lowered for. */
143     const Target &target() const;
144 
145     /** The name of this module. This is used as the default filename
146      * for output operations. */
147     const std::string &name() const;
148 
149     /** If this Module had an auto-generated schedule, return a read-only pointer
150      * to the AutoSchedulerResults. If not, return nullptr. */
151     const AutoSchedulerResults *get_auto_scheduler_results() const;
152 
153     /** Return whether this module uses strict floating-point anywhere. */
154     bool any_strict_float() const;
155 
156     /** The declarations contained in this module. */
157     // @{
158     const std::vector<Buffer<void>> &buffers() const;
159     const std::vector<Internal::LoweredFunc> &functions() const;
160     std::vector<Internal::LoweredFunc> &functions();
161     const std::vector<Module> &submodules() const;
162     const std::vector<ExternalCode> &external_code() const;
163     // @}
164 
165     /** Return the function with the given name. If no such function
166     * exists in this module, assert. */
167     Internal::LoweredFunc get_function_by_name(const std::string &name) const;
168 
169     /** Add a declaration to this module. */
170     // @{
171     void append(const Buffer<void> &buffer);
172     void append(const Internal::LoweredFunc &function);
173     void append(const Module &module);
174     void append(const ExternalCode &external_code);
175     // @}
176 
177     /** Compile a halide Module to variety of outputs, depending on
178      * the fields set in output_files. */
179     void compile(const std::map<Output, std::string> &output_files) const;
180 
181     /** Compile a halide Module to in-memory object code. Currently
182      * only supports LLVM based compilation, but should be extended to
183      * handle source code backends. */
184     Buffer<uint8_t> compile_to_buffer() const;
185 
186     /** Return a new module with all submodules compiled to buffers on
187      * on the result Module. */
188     Module resolve_submodules() const;
189 
190     /** When generating metadata from this module, remap any occurrences
191      * of 'from' into 'to'. */
192     void remap_metadata_name(const std::string &from, const std::string &to) const;
193 
194     /** Retrieve the metadata name map. */
195     std::map<std::string, std::string> get_metadata_name_map() const;
196 
197     /** Set the AutoSchedulerResults for the Module. It is an error to call this
198      * multiple times for a given Module. */
199     void set_auto_scheduler_results(const AutoSchedulerResults &results);
200 
201     /** Set whether this module uses strict floating-point directives anywhere. */
202     void set_any_strict_float(bool any_strict_float);
203 };
204 
205 /** Link a set of modules together into one module. */
206 Module link_modules(const std::string &name, const std::vector<Module> &modules);
207 
208 /** Create an object file containing the Halide runtime for a given target. For
209  * use with Target::NoRuntime. Standalone runtimes are only compatible with
210  * pipelines compiled by the same build of Halide used to call this function. */
211 void compile_standalone_runtime(const std::string &object_filename, Target t);
212 
213 /** Create an object and/or static library file containing the Halide runtime
214  * for a given target. For use with Target::NoRuntime. Standalone runtimes are
215  * only compatible with pipelines compiled by the same build of Halide used to
216  * call this function. Return a map with just the actual outputs filled in
217  * (typically, Output::object and/or Output::static_library).
218  */
219 std::map<Output, std::string> compile_standalone_runtime(const std::map<Output, std::string> &output_files, Target t);
220 
221 using ModuleFactory = std::function<Module(const std::string &fn_name, const Target &target)>;
222 using CompilerLoggerFactory = std::function<std::unique_ptr<Internal::CompilerLogger>(const std::string &fn_name, const Target &target)>;
223 
224 void compile_multitarget(const std::string &fn_name,
225                          const std::map<Output, std::string> &output_files,
226                          const std::vector<Target> &targets,
227                          const std::vector<std::string> &suffixes,
228                          const ModuleFactory &module_factory,
229                          const CompilerLoggerFactory &compiler_logger_factory = nullptr);
230 
231 }  // namespace Halide
232 
233 #endif
234