Reputation: 2445
I am working on an OpenCL Program which uses the "cl_khr_byte_addressable_store" extension to allow for byte level writes in Kernel code; in order for my program to also work on GPUs which do not support the extension, I need to check whether the extension is available and use an int
type instead of char
on platforms on which it is not.
In the kernel code, I can simply add the following snippet and use writeable_type
throughout the my kernel code; the preprocessor definition cl_khr_byte_addressable_store
is automatically added by the OpenCL Kernel compiler iff the extension is available.
/* kernel.cl */
#ifdef cl_khr_byte_addressable_store
typedef char writeable_type;
#else
typedef int writeable_type;
#endif
f() {
writeable_type x = 1;
}
In my host code I don't have that preprocessor definition, and (as far as I know) the check whether extensions are available or not can only be done at run-time:
/* host.cpp */
void execute() {
std::string extensions;
this->opencl->getExtensions(extensions);
if (extensions.find("cl_khr_byte_addressable_store") != std::string::npos) {
// extension is available
typedef cl_char writeable_type;
}
else {
// extension is not available
typedef cl_int writeable_type;
}
writeable_type x = 1;
}
And that's my problem; because typedefs are resolved at compile time and only valid within the block in which they are defined, the example above does not work.
Is it possible to somehow do this anyway?
Thanks rlc, Neil Butterworth and talonmis for putting me on the right path! The solution to my problem turns out to be fairly simple:
/*host.cpp*/
void execute() {
bool extension_available = ...;
if (extension_available)
this->_execute<cl_char>();
else
this->_execute<cl_int>();
}
template <typename writeable_char>
void _execute() {
writeable_type x = 1;
// ...
}
Upvotes: 0
Views: 1554
Reputation: 2857
if you have all your code in a class of which the public functions are agnostic of the type, you can do something like this:
// assuming these are defined in OpenCL somewhere
typedef char cl_char;
typedef int cl_int;
// the public part of the base class cannot use the
// writable size because it cannot know the size of the writable type
class Base
{
public :
/* stuff */
virtual void doStuff() = 0;
/* more stuff */
};
// the writable type's size is known in this class and is
// either cl_char or cl_int, so this is where data that has
// to know the size will be carried around, and where API calls
// that need to know the exact writable type go.
// Code that is agnostic of the writable type need not be here
// (but can be)
template < typename WritableType >
class Derived : public Base
{
public :
virtual void doStuff()
{
/* do stuff */
}
};
int main()
{
bool condition(false);
/* magic to check for type size here */
// once you get here, you know what the writable type is going to be,
// so you can create an instance of the derived class accordingly
Base *o;
if (condition)
{
o = new Derived< cl_char >;
}
else
{
o = new Derived< cl_int >;
}
// as of here, you no longer need to know what the writable type
// is because that knowledge is encapsulated in the object o
o->doStuff();
}
i.e. template the class that does everything according to the type you need at run-time, and use the version you need.
Upvotes: 2
Reputation: 146968
You're trying to alter a variable at compile-time depending on the value of something at run-time. Unless you either bring compile-time forward to run-time, such as with JITs or interpretation, or invent time travel, then the laws of physics dictate the impossibility of what you want.
Of course, you could also just remove the dependency using inheritance and virtual functions.
Upvotes: 0
Reputation: 72338
You will have to do runtime checking of the options the target OpenCL platform uses and react accordingly. Call clGetPlatformInfo
with the CL_PLATFORM_EXTENSIONS
query, and you will get back an array of characters which can be parsed to check whether cl_khr_byte_addressable_store
is supported. Then choose paths with either integer or character types accordingly.
Most of the vendor SDKs include some kind of device query app which contains examples of clGetPlatformInfo usage. You should be able to crib some code from there.
Upvotes: 1
Reputation:
All types in C++ must be known at compile time - no exceptions to this rule are possible (this is true for C too). And given the way the language is defined, attempts to redefine types at runtime simply do not make sense. If you find you think you need to do this, there is something way wrong with your design.
Upvotes: 1