Hello,
Yes, the pieces are coming together. Today, a new word appeared in the list of supported features of Clover : kernels. Clover can now extract them from programs and do some interesting things with them, for instance listing their parameters (and types). It's for the moment the only "big" thing it can do, but there is more to come.
Implementing the kernels was a nice experience. I fact, the current days of Clover development are very exciting. I have to use many technologies and projects, like Clang, LLVM, the STL, and event Check (Clover's unit testing framework). All is very nice and well done, and pretty diversified. It goes from the thousand-classes LLVM to the "small" STL doing just what it needs to.
Speaking about the STL, I have a question for the few C++-experts reading this blog. The OpenCL specification says that: “Kernel objects are not created for any __kernel functions in program that do not have the same function definition across all devices for which a program executable has been successfully built." This means that I need to keep a set of the kernels available in all the "per-device sub-programs" (the function definition is verified after).
Doing that is like a SELECT ... INNER JOINT in SQL. We can also express it with the following pseudocode :
1 2 3 4 5 6 | kernels is a set
for (subprogram in subprograms)
if (kernels.empty)
kernels = subprogram.kernels
else
kernels &= subprogram.kernels // This line
|
I'm currently doing this in C++ using std::set, but I'm not comfortable with my current code :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | std::set<std::string> kernels_set;
for (int i=0; i<p_device_dependent.size(); ++i)
{
DeviceDependent &dep = p_device_dependent.at(i);
std::vector<llvm::Function *> kernels = kernelFunctions(dep);
std::set<std::string> set;
// Add the kernels in the set
for (int j=0; j<kernels.size(); ++j)
{
llvm::Function *func = kernels.at(j);
set.insert(func->getNameStr());
}
// intersection of the sets
if (kernels_set.empty())
{
kernels_set = set;
}
else
{
std::set<std::string> inter;
set_intersection(set.begin(),
set.end(),
kernels_set.begin(),
kernels_set.end(),
std::inserter(inter, inter.begin()));
kernels_set = inter;
}
}
|
The problem is that I don't know if it's the best way to do that (or a sufficiently good one). Qt has a good function to do this without a temporary set, but the STL lacks one. I don't know if I can use the same std::set in the source parts of set_intersection and as the result set.
Except that, the code should not be too ugly, and it works fairly well. I thank Zack Rusin for having added unit tests in Clover (and I'm happy to have continued to implement them), it's very pleasant to type "make test", to see that all goes well, and to think "my code is ok :) ".