#ifndef HALIDE_EXTERNAL_CODE_H #define HALIDE_EXTERNAL_CODE_H #include <vector> #include "Expr.h" #include "Target.h" namespace Halide { class ExternalCode { private: enum Kind { LLVMBitcode, DeviceCode, CPlusPlusSource, } kind; Target llvm_target; // For LLVMBitcode. DeviceAPI device_code_kind; std::vector<uint8_t> code; // Used for debugging and naming the module to llvm. std::string nametag; ExternalCode(Kind kind, const Target &llvm_target, DeviceAPI device_api, const std::vector<uint8_t> &code, const std::string &name) : kind(kind), llvm_target(llvm_target), device_code_kind(device_api), code(code), nametag(name) { } public: /** Construct an ExternalCode container from llvm bitcode. The * result can be passed to Halide::Module::append to have the * contained bitcode linked with that module. The Module's target * must match the target argument here on architecture, bit width, * and operating system. The name is used as a unique identifier * for the external code and duplicates will be reduced to a * single instance. Halide does not do anything other than to * compare names for equality. To guarantee uniqueness in public * code, we suggest using a Java style inverted domain name * followed by organization specific naming. E.g.: * com.initech.y2k.5d2ac80aaf522eec6cb4b40f39fb923f9902bc7e */ static ExternalCode bitcode_wrapper(const Target &cpu_type, const std::vector<uint8_t> &code, const std::string &name) { return ExternalCode(LLVMBitcode, cpu_type, DeviceAPI::None, code, name); } /** Construct an ExternalCode container from GPU "source code." * This container can be used to insert its code into the GPU code * generated for a given DeviceAPI. The specific type of code * depends on the device API used as follows: * CUDA: llvm bitcode for PTX * OpenCL: OpenCL source code * GLSL: GLSL source code * OpenGLCompute: GLSL source code * Metal: Metal source code * Hexagon: llvm bitcode for Hexagon * * At present, this API is not fully working. See Issue: * https://github.com/halide/Halide/issues/1971 * * The name is used as a unique identifier for the external code * and duplicates will be reduced to a single instance. Halide * does not do anything other than to compare names for * equality. To guarantee uniqueness in public code, we suggest * using a Java style inverted domain name followed by * organization specific naming. E.g.: * com.tyrell.nexus-6.53947db86ba97a9ca5ecd5e60052880945bfeb37 */ static ExternalCode device_code_wrapper(DeviceAPI device_api, const std::vector<uint8_t> &code, const std::string &name) { return ExternalCode(DeviceCode, Target(), device_api, code, name); } /** Construct an ExternalCode container from C++ source code. This * container can be used to insert its code into C++ output from * Halide. * * At present, this API is not fully working. See Issue: * https://github.com/halide/Halide/issues/1971 * * The name is used as a unique identifier for the external code * and duplicates will be reduced to a single instance. Halide * does not do anything other than to compare names for * equality. To guarantee uniqueness in public code, we suggest * using a Java style inverted domain name followed by * organization specific naming. E.g.: * com.cyberdyne.skynet.78ad6c411d313f050f172cd3d440f23fdd797d0d */ static ExternalCode c_plus_plus_code_wrapper(const std::vector<uint8_t> &code, const std::string &name) { return ExternalCode(CPlusPlusSource, Target(), DeviceAPI::None, code, name); } /** Return true if this container holds llvm bitcode linkable with * code generated for the target argument. The matching is done * on the architecture, bit width, and operating system * only. Features are ignored. If the container is for * Target::ArchUnkonwn, it applies to all architectures -- meaning * it is generic llvm bitcode. If the OS is OSUnknown, it applies * to all operationg systems. The bit width must match. * * Ignoring feature flags isn't too important since generally * ExternalCode will be constructed in a Generator which has * access to the feature flags in effect and can select code * appropriately. */ bool is_for_cpu_target(const Target &host) const { return kind == LLVMBitcode && (llvm_target.arch == Target::ArchUnknown || llvm_target.arch == host.arch) && (llvm_target.os == Target::OSUnknown || llvm_target.os == host.os) && (llvm_target.bits == host.bits); } /** True if this container holds code linkable with a code generated for a GPU. */ bool is_for_device_api(DeviceAPI current_device) const { return kind == DeviceCode && device_code_kind == current_device; } /** True if this container holds C++ source code for inclusion in * generating C++ output. */ bool is_c_plus_plus_source() const { return kind == CPlusPlusSource; } /** Retrieve the bytes of external code held by this container. */ const std::vector<uint8_t> &contents() const { return code; } /** Retrieve the name of this container. Used to ensure the same * piece of external code is only included once in linkage. */ const std::string &name() const { return nametag; } }; } #endif