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