1 #ifndef HALIDE_DEVICE_ARGUMENT_H
2 #define HALIDE_DEVICE_ARGUMENT_H
3 
4 /** \file
5  * Defines helpers for passing arguments to separate devices, such as GPUs.
6  */
7 #include <string>
8 
9 #include "Closure.h"
10 #include "Expr.h"
11 #include "ModulusRemainder.h"
12 
13 namespace Halide {
14 namespace Internal {
15 
16 /** A DeviceArgument looks similar to an Halide::Argument, but has behavioral
17  * differences that make it specific to the GPU pipeline; the fact that
18  * neither is-a nor has-a Halide::Argument is deliberate. In particular, note
19  * that a Halide::Argument that is a buffer can be read or write, but not both,
20  * while a DeviceArgument that is a buffer can be read *and* write for some GPU
21  * backends. */
22 struct DeviceArgument {
23     /** The name of the argument */
24     std::string name;
25 
26     /** An argument is either a primitive type (for parameters), or a
27      * buffer pointer.
28      *
29      * If is_buffer == false, then type fully encodes the expected type
30      * of the scalar argument.
31      *
32      * If is_buffer == true, then type.bytes() should be used to determine
33      * elem_size of the buffer; additionally, type.code *should* reflect
34      * the expected interpretation of the buffer data (e.g. float vs int),
35      * but there is no runtime enforcement of this at present.
36      */
37     bool is_buffer;
38 
39     /** If is_buffer is true, this is the dimensionality of the buffer.
40      * If is_buffer is false, this value is ignored (and should always be set to zero) */
41     uint8_t dimensions;
42 
43     /** If this is a scalar parameter, then this is its type.
44      *
45      * If this is a buffer parameter, this is used to determine elem_size
46      * of the halide_buffer_t.
47      *
48      * Note that type.lanes() should always be 1 here. */
49     Type type;
50 
51     /** The static size of the argument if known, or zero otherwise. */
52     size_t size;
53 
54     /** The index of the first element of the argument when packed into a wider
55      * type, such as packing scalar floats into vec4 for GLSL. */
56     size_t packed_index;
57 
58     /** For buffers, these two variables can be used to specify whether the
59      * buffer is read or written. By default, we assume that the argument
60      * buffer is read-write and set both flags. */
61     bool read;
62     bool write;
63 
64     /** Alignment information for integer parameters. */
65     ModulusRemainder alignment;
66 
DeviceArgumentDeviceArgument67     DeviceArgument()
68         : is_buffer(false),
69           dimensions(0),
70           size(0),
71           packed_index(0),
72           read(false),
73           write(false) {
74     }
75 
76     DeviceArgument(const std::string &_name,
77                    bool _is_buffer,
78                    Type _type,
79                    uint8_t _dimensions,
80                    size_t _size = 0)
nameDeviceArgument81         : name(_name),
82           is_buffer(_is_buffer),
83           dimensions(_dimensions),
84           type(_type),
85           size(_size),
86           packed_index(0),
87           read(_is_buffer),
88           write(_is_buffer) {
89     }
90 };
91 
92 /** A Closure modified to inspect GPU-specific memory accesses, and
93  * produce a vector of DeviceArgument objects. */
94 class HostClosure : public Closure {
95 public:
96     HostClosure(const Stmt &s, const std::string &loop_variable = "");
97 
98     /** Get a description of the captured arguments. */
99     std::vector<DeviceArgument> arguments();
100 
101 protected:
102     using Internal::Closure::visit;
103     void visit(const For *loop) override;
104     void visit(const Call *op) override;
105 };
106 
107 }  // namespace Internal
108 }  // namespace Halide
109 
110 #endif
111