clReleaseDevice,
clCreateImage,
clCreateProgramWithBuiltInKernels,
- NULL, // clCompileProgram
+ clCompileProgram,
NULL, // clLinkProgram
clUnloadPlatformCompiler,
NULL, // clGetKernelArgInfo
clBuildProgram(cl_program d_prog, cl_uint num_devs,
const cl_device_id *d_devs, const char *p_opts,
void (*pfn_notify)(cl_program, void *),
- void *user_data) try {
+ void *user_data) {
+ cl_int ret = clCompileProgram(d_prog, num_devs, d_devs, p_opts,
+ 0, NULL, NULL, pfn_notify, user_data);
+
+ return (ret == CL_COMPILE_PROGRAM_FAILURE ?
+ CL_BUILD_PROGRAM_FAILURE : ret);
+}
+
+CLOVER_API cl_int
+clCompileProgram(cl_program d_prog, cl_uint num_devs,
+ const cl_device_id *d_devs, const char *p_opts,
+ cl_uint num_headers, const cl_program *d_header_progs,
+ const char **header_names,
+ void (*pfn_notify)(cl_program, void *),
+ void *user_data) try {
auto &prog = obj(d_prog);
auto devs = (d_devs ? objs(d_devs, num_devs) :
ref_vector<device>(prog.context().devices()));
auto opts = (p_opts ? p_opts : "");
+ header_map headers;
if (bool(num_devs) != bool(d_devs) ||
- (!pfn_notify && user_data))
+ (!pfn_notify && user_data) ||
+ bool(num_headers) != bool(header_names))
throw error(CL_INVALID_VALUE);
if (any_of([&](const device &dev) {
}, devs))
throw error(CL_INVALID_DEVICE);
- if (prog.kernel_ref_count())
+ if (prog.kernel_ref_count() ||
+ !prog.has_source)
throw error(CL_INVALID_OPERATION);
- prog.build(devs, opts);
+
+ for_each([&](const char *name, const program &header) {
+ if (!header.has_source)
+ throw error(CL_INVALID_OPERATION);
+
+ if (!any_of(key_equals(name), headers))
+ headers.push_back(compat::pair<compat::string, compat::string>(
+ name, header.source()));
+ },
+ range(header_names, num_headers),
+ objs(d_header_progs, num_headers));
+
+ prog.build(devs, opts, headers);
return CL_SUCCESS;
} catch (error &e) {
#include "pipe/p_defines.h"
namespace clover {
+ typedef compat::vector<compat::pair<compat::string,
+ compat::string> > header_map;
+
module compile_program_llvm(const compat::string &source,
+ const header_map &headers,
pipe_shader_ir ir,
const compat::string &target,
const compat::string &opts,
class build_error : public error {
public:
build_error(const compat::string &what = "") :
- error(CL_BUILD_PROGRAM_FAILURE, what) {
+ error(CL_COMPILE_PROGRAM_FAILURE, what) {
}
};
//
#include "core/program.hpp"
-#include "core/compiler.hpp"
using namespace clover;
}
void
-program::build(const ref_vector<device> &devs, const char *opts) {
+program::build(const ref_vector<device> &devs, const char *opts,
+ const header_map &headers) {
if (has_source) {
_devices = devs;
try {
auto module = (dev.ir_format() == PIPE_SHADER_IR_TGSI ?
compile_program_tgsi(_source) :
- compile_program_llvm(_source, dev.ir_format(),
+ compile_program_llvm(_source, headers,
+ dev.ir_format(),
dev.ir_target(), build_opts(dev),
log));
_binaries.insert({ &dev, module });
#include "core/object.hpp"
#include "core/context.hpp"
#include "core/module.hpp"
+#include "core/compiler.hpp"
namespace clover {
class program : public ref_counter, public _cl_program {
program &
operator=(const program &prog) = delete;
- void build(const ref_vector<device> &devs, const char *opts);
+ void build(const ref_vector<device> &devs, const char *opts,
+ const header_map &headers);
const bool has_source;
const std::string &source() const;
llvm::Module *
compile_llvm(llvm::LLVMContext &llvm_ctx, const std::string &source,
- const std::string &name, const std::string &triple,
- const std::string &processor, const std::string &opts,
- clang::LangAS::Map& address_spaces, unsigned &optimization_level,
- compat::string &r_log) {
+ const header_map &headers,
+ const std::string &name, const std::string &triple,
+ const std::string &processor, const std::string &opts,
+ clang::LangAS::Map& address_spaces, unsigned &optimization_level,
+ compat::string &r_log) {
clang::CompilerInstance c;
clang::EmitLLVMOnlyAction act(&llvm_ctx);
llvm::MemoryBuffer::getMemBuffer(source));
#endif
+ if (headers.size()) {
+ const std::string tmp_header_path = "/tmp/clover/";
+
+ c.getHeaderSearchOpts().AddPath(tmp_header_path,
+ clang::frontend::Angled,
+ false, false
+#if HAVE_LLVM < 0x0303
+ , false
+#endif
+ );
+
+ for (header_map::const_iterator it = headers.begin();
+ it != headers.end(); ++it) {
+ const std::string path = tmp_header_path + std::string(it->first);
+ c.getPreprocessorOpts().addRemappedFile(path,
+#if HAVE_LLVM >= 0x0306
+ llvm::MemoryBuffer::getMemBuffer(it->second.c_str()).release());
+#else
+ llvm::MemoryBuffer::getMemBuffer(it->second.c_str()));
+#endif
+ }
+ }
+
// Setting this attribute tells clang to link this file before
// performing any optimizations. This is required so that
// we can replace calls to the OpenCL C barrier() builtin
module
clover::compile_program_llvm(const compat::string &source,
+ const header_map &headers,
enum pipe_shader_ir ir,
const compat::string &target,
const compat::string &opts,
// The input file name must have the .cl extension in order for the
// CompilerInvocation class to recognize it as an OpenCL source file.
- llvm::Module *mod = compile_llvm(llvm_ctx, source, "input.cl", triple,
- processor, opts, address_spaces,
+ llvm::Module *mod = compile_llvm(llvm_ctx, source, headers, "input.cl",
+ triple, processor, opts, address_spaces,
optimization_level, r_log);
find_kernels(mod, kernels);