Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
26d0076
yes
jlaxson Sep 24, 2020
25d31da
woof
jlaxson Sep 24, 2020
76895bd
Handle mins
jlaxson Sep 24, 2020
ef4e9b0
cleanup
jlaxson Sep 24, 2020
e7e8ac1
runtime helpers
jlaxson Sep 24, 2020
a54d822
bye
jlaxson Sep 24, 2020
33d589d
add remaining device interface methods
jlaxson Sep 24, 2020
63397d4
cleanup
jlaxson Sep 24, 2020
f5d0427
move store_in to OutputImageParam
jlaxson Sep 24, 2020
41abcf2
Revert "move store_in to OutputImageParam"
jlaxson Sep 24, 2020
5030108
move store_in to OutputImageParam
jlaxson Sep 24, 2020
8382eff
Output support and generator test
jlaxson Sep 25, 2020
b36aab3
fix bypassed test
jlaxson Sep 26, 2020
511082c
build fixes
jlaxson Sep 30, 2020
dbad5b1
comment
jlaxson Sep 30, 2020
2f2c164
Merge branch 'master' into pr/5297_2
steven-johnson Sep 30, 2020
979b05a
assert me not
jlaxson Sep 30, 2020
4141309
more assert/error cleanup
jlaxson Sep 30, 2020
c0f09a8
intrinsic rename, cleanup
jlaxson Oct 2, 2020
b8348e0
format
jlaxson Oct 2, 2020
2736267
Fix signed/unsigned comparison issue
steven-johnson Oct 2, 2020
023c2c8
Merge branch 'master' into pr/5297
steven-johnson Oct 2, 2020
679445a
Merge branch 'master' into pr/5297
steven-johnson Oct 5, 2020
a4137b6
Set storage for Buffer<> nodes
jlaxson Oct 6, 2020
dec6954
redundancies have been made redundant
jlaxson Oct 6, 2020
c5363c7
Merge branch 'master' into pr/5297
steven-johnson Oct 6, 2020
b905086
touched_as_texture is dead
jlaxson Oct 8, 2020
64d1506
Guard texture with OpenCL
jlaxson Oct 8, 2020
502e685
lint
jlaxson Oct 8, 2020
4bb4efe
Merge remote-tracking branch 'origin/master' into opencl-texture
jlaxson Oct 8, 2020
89d5984
Merge branch 'master' into pr/5297
steven-johnson Oct 9, 2020
b6d1d3d
Merge branch 'master' into pr/5297
steven-johnson Oct 12, 2020
537d54c
Check OpenCL version on tests
jlaxson Oct 13, 2020
b7533f9
Merge remote-tracking branch 'origin/master' into opencl-texture
jlaxson Oct 13, 2020
ccb3427
Merge branch 'opencl-texture' of github.com:jlaxson/Halide into openc…
jlaxson Oct 13, 2020
634741a
Merge branch 'master' into pr/5297
steven-johnson Oct 14, 2020
55d1a88
Avoid unused-variable error
steven-johnson Oct 14, 2020
f80455f
Avoid another unused-variable error
steven-johnson Oct 14, 2020
63df7ac
Merge branch 'master' into pr/5297
steven-johnson Oct 14, 2020
5b958b7
Skip generator_aotcpp_gpu_texture in tests
steven-johnson Oct 16, 2020
13f0815
Merge branch 'master' into pr/5297
steven-johnson Oct 19, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -1100,6 +1100,9 @@ GENERATOR_AOTCPP_TESTS := $(filter-out generator_aotcpp_multitarget,$(GENERATOR_
# remove AOT-CPP tests that don't (yet) work for C++ backend
# (each tagged with the *known* blocking issue(s))

# https://github.com/halide/Halide/issues/2084 (only if opencl enabled)
GENERATOR_AOTCPP_TESTS := $(filter-out generator_aotcpp_gpu_texture,$(GENERATOR_AOTCPP_TESTS))

# https://github.com/halide/Halide/issues/2084 (only if opencl enabled)
GENERATOR_AOTCPP_TESTS := $(filter-out generator_aotcpp_acquire_release,$(GENERATOR_AOTCPP_TESTS))

Expand Down
5 changes: 4 additions & 1 deletion python_bindings/src/PyEnums.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ void define_enums(py::module &m) {
.value("Heap", MemoryType::Heap)
.value("Stack", MemoryType::Stack)
.value("Register", MemoryType::Register)
.value("GPUShared", MemoryType::GPUShared);
.value("GPUShared", MemoryType::GPUShared)
.value("GPUTexture", MemoryType::GPUTexture)
.value("LockedCache", MemoryType::LockedCache)
.value("VTCM", MemoryType::VTCM);

py::enum_<NameMangling>(m, "NameMangling")
.value("Default", NameMangling::Default)
Expand Down
1 change: 1 addition & 0 deletions python_bindings/src/PyImageParam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ void define_image_param(py::module &m) {
.def("host_alignment", &OutputImageParam::host_alignment)
.def("set_estimates", &OutputImageParam::set_estimates, py::arg("estimates"))
.def("set_host_alignment", &OutputImageParam::set_host_alignment)
.def("store_in", &OutputImageParam::store_in, py::arg("memory_type"))
.def("dimensions", &OutputImageParam::dimensions)
.def("left", &OutputImageParam::left)
.def("right", &OutputImageParam::right)
Expand Down
5 changes: 4 additions & 1 deletion src/Closure.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,14 @@ class Closure : public IRVisitor {
/** The buffer is written to. */
bool write;

/** The buffer is a texture */
MemoryType memory_type;

/** The size of the buffer if known, otherwise zero. */
size_t size;

Buffer()
: dimensions(0), read(false), write(false), size(0) {
: dimensions(0), read(false), write(false), memory_type(MemoryType::Auto), size(0) {
}
};

Expand Down
147 changes: 140 additions & 7 deletions src/CodeGen_OpenCL_Dev.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <algorithm>
#include <array>
#include <sstream>
#include <utility>

Expand Down Expand Up @@ -174,6 +175,21 @@ string CodeGen_OpenCL_Dev::CodeGen_OpenCL_C::get_memory_space(const string &buf)
}
}

namespace {
std::string image_type_suffix(const Type &type) {
if (type.is_int()) {
return "i";
} else if (type.is_uint()) {
return "ui";
} else if (type.is_float()) {
return "f";
} else {
internal_error << "Invalid type for image: " << type << "\n";
}
return "";
}
} // namespace

void CodeGen_OpenCL_Dev::CodeGen_OpenCL_C::visit(const Call *op) {
if (op->is_intrinsic(Call::bool_to_mask)) {
if (op->args[0].type().is_vector()) {
Expand Down Expand Up @@ -242,6 +258,107 @@ void CodeGen_OpenCL_Dev::CodeGen_OpenCL_C::visit(const Call *op) {
} else {
CodeGen_C::visit(op);
}
} else if (op->is_intrinsic(Call::image_load)) {
// image_load(<image name>, <buffer>, <x>, <x-extent>, <y>,
// <y-extent>, <z>, <z-extent>)
int dims = (op->args.size() - 2) / 2;
internal_assert(dims >= 1 && dims <= 3);
const StringImm *string_imm = op->args[0].as<StringImm>();
if (!string_imm) {
internal_assert(op->args[0].as<Broadcast>());
string_imm = op->args[0].as<Broadcast>()->value.as<StringImm>();
}
internal_assert(string_imm);
Type arg_type = op->args[2].type();
internal_assert(arg_type.lanes() <= 16);
internal_assert(arg_type.lanes() == op->type.lanes());

std::array<string, 3> coord;
for (int i = 0; i < dims; i++) {
coord[i] = print_expr(op->args[i * 2 + 2]);
}
vector<string> results(arg_type.lanes());
// For vectorized reads, codegen as a sequence of read_image calls
for (int i = 0; i < arg_type.lanes(); i++) {
ostringstream rhs;
rhs << "read_image" << image_type_suffix(op->type) << "(" << print_name(string_imm->value) << ", ";
string idx = arg_type.is_vector() ? string(".s") + vector_elements[i] : "";
switch (dims) {
case 1:
rhs << coord[0] << idx << ").s0";
break;
case 2:
rhs << "(int2)(" << coord[0] << idx << ", " << coord[1] << idx << ")).s0";
break;
case 3:
rhs << "(int4)(" << coord[0] << idx << ", " << coord[1] << idx
<< ", " << coord[2] << idx << ", 0)).s0";
break;
}
print_assignment(op->type.with_bits(32).with_lanes(1), rhs.str());
results[i] = id;
}

if (op->type.is_vector()) {
// Combine all results into a single vector
ostringstream rhs;
rhs << "(" << print_type(op->type) << ")(";
for (int i = 0; i < op->type.lanes(); i++) {
rhs << results[i];
if (i < op->type.lanes() - 1) {
rhs << ", ";
}
}
rhs << ")";
print_assignment(op->type, rhs.str());
}
if (op->type.bits() != 32) {
// Widen to the correct type
print_assignment(op->type, "convert_" + print_type(op->type) + "(" + id + ")");
}
} else if (op->is_intrinsic(Call::image_store)) {
// image_store(<image name>, <buffer>, <x>, <y>, <z>, <value>)
const StringImm *string_imm = op->args[0].as<StringImm>();
if (!string_imm) {
internal_assert(op->args[0].as<Broadcast>());
string_imm = op->args[0].as<Broadcast>()->value.as<StringImm>();
}
internal_assert(string_imm);
int dims = op->args.size() - 3;
internal_assert(dims >= 1 && dims <= 3);
Type arg_type = op->args[2].type();
internal_assert(arg_type.lanes() <= 16);
Type value_type = op->args.back().type();
internal_assert(arg_type.lanes() == value_type.lanes());

std::array<string, 3> coord;
for (int i = 0; i < dims; i++) {
coord[i] = print_expr(op->args[i + 2]);
}
string value = print_expr(op->args.back());
// For vectorized writes, codegen as a sequence of write_image calls
for (int i = 0; i < arg_type.lanes(); i++) {
ostringstream write_image;
write_image << "write_image" << image_type_suffix(op->type)
<< "(" << print_name(string_imm->value) << ", ";
string idx = arg_type.is_vector() ? string(".s") + vector_elements[i] : "";
switch (dims) {
case 1:
write_image << coord[0] << idx;
break;
case 2:
write_image << "(int2)(" << coord[0] << idx << ", " << coord[1] << idx << ")";
break;
case 3:
write_image << "(int4)(" << coord[0] << idx << ", " << coord[1] << idx
<< ", " << coord[2] << idx << ", 0)";
break;
}
write_image << ", (" << print_type(value_type.with_bits(32).with_lanes(4))
<< ")(" << value << idx << ", 0, 0, 0));\n";
// do_indent();
stream << write_image.str();
}
} else {
CodeGen_C::visit(op);
}
Expand Down Expand Up @@ -765,13 +882,29 @@ void CodeGen_OpenCL_Dev::CodeGen_OpenCL_C::add_kernel(Stmt s,
stream << "__kernel void " << name << "(\n";
for (size_t i = 0; i < args.size(); i++) {
if (args[i].is_buffer) {
stream << " " << get_memory_space(args[i].name) << " ";
if (!args[i].write) {
stream << "const ";
if (args[i].memory_type == MemoryType::GPUTexture) {
int dims = args[i].dimensions;
internal_assert(dims >= 1 && dims <= 3) << "dims = " << dims << "\n";
if (args[i].read && args[i].write) {
stream << " __read_write ";
} else if (args[i].read) {
stream << " __read_only ";
} else if (args[i].write) {
stream << " __write_only ";
} else {
internal_error << "CL Image argument " << args[i].name
<< " is neither read nor write";
}
stream << "image" << dims << "d_t ";
} else {
stream << " " << get_memory_space(args[i].name) << " ";
if (!args[i].write) {
stream << "const ";
}
stream << print_type(args[i].type) << " *"
<< "restrict ";
}
stream << print_type(args[i].type) << " *"
<< "restrict "
<< print_name(args[i].name);
stream << print_name(args[i].name);
Allocation alloc;
alloc.type = args[i].type;
allocations.push(args[i].name, alloc);
Expand Down Expand Up @@ -801,7 +934,7 @@ void CodeGen_OpenCL_Dev::CodeGen_OpenCL_C::add_kernel(Stmt s,
void visit(const Allocate *op) override {
if (op->memory_type == MemoryType::GPUShared) {
internal_assert(alloc == nullptr)
<< "Found multiple shared allocations in metal kernel\n";
<< "Found multiple shared allocations in opencl kernel\n";
alloc = op;
}
}
Expand Down
15 changes: 12 additions & 3 deletions src/DeviceArgument.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ std::vector<DeviceArgument> HostClosure::arguments() {
std::vector<DeviceArgument> res;
for (const auto &v : vars) {
debug(2) << "var: " << v.first << "\n";
res.emplace_back(v.first, false, v.second, 0);
res.emplace_back(v.first, false, MemoryType::Auto, v.second, 0);
}
for (const auto &b : buffers) {
debug(2) << "buffer: " << b.first << " " << b.second.size;
Expand All @@ -25,9 +25,13 @@ std::vector<DeviceArgument> HostClosure::arguments() {
if (b.second.write) {
debug(2) << " (write)";
}
if (b.second.memory_type == MemoryType::GPUTexture) {
debug(2) << " <texture>";
}
debug(2) << " dims=" << (int)b.second.dimensions;
debug(2) << "\n";

DeviceArgument arg(b.first, true, b.second.type, b.second.dimensions, b.second.size);
DeviceArgument arg(b.first, true, b.second.memory_type, b.second.type, b.second.dimensions, b.second.size);
arg.read = b.second.read;
arg.write = b.second.write;
res.push_back(arg);
Expand Down Expand Up @@ -55,14 +59,19 @@ void HostClosure::visit(const Call *op) {
std::string bufname = string_imm->value;
Buffer &ref = buffers[bufname];
ref.type = op->type;
// TODO: do we need to set ref.dimensions?
ref.memory_type = op->is_intrinsic(Call::image_load) ||
op->is_intrinsic(Call::image_store) ?
MemoryType::GPUTexture :
MemoryType::Auto;

if (op->is_intrinsic(Call::glsl_texture_load) ||
op->is_intrinsic(Call::image_load)) {
ref.read = true;
ref.dimensions = (op->args.size() - 2) / 2;
} else if (op->is_intrinsic(Call::glsl_texture_store) ||
op->is_intrinsic(Call::image_store)) {
ref.write = true;
ref.dimensions = op->args.size() - 3;
}

// The Func's name and the associated .buffer are mentioned in the
Expand Down
9 changes: 9 additions & 0 deletions src/DeviceArgument.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ struct DeviceArgument {
*/
bool is_buffer;

/** If is_buffer == true and memory_type == GPUTexture, this argument should be
* passed and accessed through texture sampler operations instead of
* directly as a memory array
*/
MemoryType memory_type;

/** If is_buffer is true, this is the dimensionality of the buffer.
* If is_buffer is false, this value is ignored (and should always be set to zero) */
uint8_t dimensions;
Expand Down Expand Up @@ -66,6 +72,7 @@ struct DeviceArgument {

DeviceArgument()
: is_buffer(false),
memory_type(MemoryType::Auto),
dimensions(0),
size(0),
packed_index(0),
Expand All @@ -75,11 +82,13 @@ struct DeviceArgument {

DeviceArgument(const std::string &_name,
bool _is_buffer,
MemoryType _mem,
Type _type,
uint8_t _dimensions,
size_t _size = 0)
: name(_name),
is_buffer(_is_buffer),
memory_type(_mem),
dimensions(_dimensions),
type(_type),
size(_size),
Expand Down
8 changes: 6 additions & 2 deletions src/DeviceInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ DeviceAPI get_default_device_api_for_target(const Target &target) {
}

namespace Internal {
Expr make_device_interface_call(DeviceAPI device_api) {
Expr make_device_interface_call(DeviceAPI device_api, MemoryType memory_type) {
if (device_api == DeviceAPI::Host) {
return make_zero(type_of<const halide_device_interface_t *>());
}
Expand All @@ -175,7 +175,11 @@ Expr make_device_interface_call(DeviceAPI device_api) {
interface_name = "halide_cuda_device_interface";
break;
case DeviceAPI::OpenCL:
interface_name = "halide_opencl_device_interface";
if (memory_type == MemoryType::GPUTexture) {
interface_name = "halide_opencl_image_device_interface";
} else {
interface_name = "halide_opencl_device_interface";
}
break;
case DeviceAPI::Metal:
interface_name = "halide_metal_device_interface";
Expand Down
3 changes: 2 additions & 1 deletion src/DeviceInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Methods for managing device allocations when jitting
*/

#include "Expr.h"
#include "Target.h"

namespace Halide {
Expand Down Expand Up @@ -37,7 +38,7 @@ bool host_supports_target_device(const Target &t);

namespace Internal {
/** Get an Expr which evaluates to the device interface for the given device api at runtime. */
Expr make_device_interface_call(DeviceAPI device_api);
Expr make_device_interface_call(DeviceAPI device_api, MemoryType memory_type = MemoryType::Auto);
} // namespace Internal

} // namespace Halide
Expand Down
4 changes: 4 additions & 0 deletions src/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,10 @@ enum class MemoryType {
* across GPU threads within the same block. */
GPUShared,

/** Allocation is stored in GPU texture memory and accessed through
* hardware sampler */
GPUTexture,

/** Allocate Locked Cache Memory to act as local memory */
LockedCache,
/** Vector Tightly Coupled Memory. HVX (Hexagon) local memory available on
Expand Down
6 changes: 5 additions & 1 deletion src/FuseGPUThreadLoops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,8 @@ class ExtractSharedAndHeapAllocations : public IRMutator {

if ((fixed_size_thread_allocation &&
op->memory_type != MemoryType::Heap &&
op->memory_type != MemoryType::GPUShared) ||
op->memory_type != MemoryType::GPUShared &&
op->memory_type != MemoryType::GPUTexture) ||
op->memory_type == MemoryType::Register ||
op->memory_type == MemoryType::Stack) {
// These allocations go in register or local memory
Expand All @@ -467,6 +468,7 @@ class ExtractSharedAndHeapAllocations : public IRMutator {

user_assert(op->memory_type == MemoryType::Auto ||
op->memory_type == MemoryType::GPUShared ||
op->memory_type == MemoryType::GPUTexture ||
op->memory_type == MemoryType::Heap)
<< "Allocation " << op->name << " must live in shared or heap memory, "
<< "but is scheduled to live in " << op->memory_type << " memory.\n";
Expand Down Expand Up @@ -1265,6 +1267,7 @@ class InjectThreadBarriers : public IRMutator {
break;
case MemoryType::Auto:
case MemoryType::Heap:
case MemoryType::GPUTexture:
debug(4) << " memory type is heap or auto\n";
device_stores.insert(op->name);
break;
Expand All @@ -1288,6 +1291,7 @@ class InjectThreadBarriers : public IRMutator {
break;
case MemoryType::Auto:
case MemoryType::Heap:
case MemoryType::GPUTexture:
debug(4) << " memory type is heap or auto\n";
device_loads.insert(op->name);
break;
Expand Down
Loading