- edited description
constexpr constructor and compile time execution
Hi!
First of all let me thank you for providing such a great numerical library to the community.
As a part of our research we aim to implement complex algorithms to solve systems of equations at compile time with GCC 8.2.
Let me include a simple example here:
#include <array>
template <std::size_t nr, std::size_t nc, typename number>
constexpr std::array<number,nr>
operator *(const std::array<std::array<number,nc>,nr> & A,const std::array<number,nc> & x)
{
std::array<number,nr> res{} ;
for (auto i=0u;i<nr;++i)
for (auto j=0u;j<nc;++j)
res[i] += A[i][j]*x[j];
return res ;
}
constexpr auto mymain()
{
const std::array<double,4> x{1.,2.,3.,4.};
const std::array<std::array<double,4>,4> A{std::array<double,4>{1.,2.,3.,4.},
std::array<double,4>{5.,6.,7.,8.},
std::array<double,4>{9.,10.,11.,12.},
std::array<double,4>{13.,14.,15.,16.}};
const std::array<double,4> res = A*x;
return res ;
}
int main(int argc, char *argv[])
{
const volatile auto res = mymain();
return 0;
}
Such a code generates an assembly containing the result res
in the data section:
22 .data
23 .align 32
26 res.31806:
27 0000 00000000 .long 0
28 0004 00003E40 .long 1077805056
29 0008 00000000 .long 0
30 000c 00805140 .long 1079083008
31 0010 00000000 .long 0
32 0014 00805B40 .long 1079738368
33 0018 00000000 .long 0
34 001c 00C06240 .long 1080213504
I would love to use Blaze and all its resources for my project, a similar code written with Blaze would look like:
#include <blaze/Math.h>
constexpr auto mymain()
{
const blaze::StaticVector<double,4> x{1.,2.,3.,4.};
const blaze::StaticMatrix<double,4,4> A{{1.,2.,3.,4.},
{5.,6.,7.,8.},
{9.,10.,11.,12.},
{13.,14.,15.,16.}};
const blaze::StaticVector<double,4> res = A*x;
return res ;
}
int main(int argc, char *argv[])
{
const volatile auto res = mymain();
return 0;
}
However this does not compile because StaticMatrix
and StaticVector
have no constexpr
constructor.
Is there any interest in implementing such constructors? If there is, could I be of any help? Or, on the other hand, am I misunderstanding how Blaze should be used for compile-time calculations?
I am compiling with the following command:
g++ -I/path/to/blaze/include -march=native -std=c++1z -Ofast -DNDEBUG -ftree-vectorizer-verbose=9 -fopt-info-optall=vec_report -Wa,-adhln -g source.cc -o exec > assembly.s
Thanks for your attention.
Best!
Comments (12)
-
reporter -
Hi Astor!
Thanks a lot for creating this issue. This question has been raised before (see issue #163) and indeed this would be a logical extension for static vectors and matrices. Unfortunately we are building on intrinsics for all arithmetic operations (addition, subtraction, multiplications, etc.). These functions give us control over SIMD statements, which we need to achieve maximum performance at runtime. Unfortunately these functions are not
constexpr
, so cannot be used for compile time computations. Therefore we would need additional kernels for the compile time computations. Unfortunately, at this point in time it is not possible to overload onconstexpr
or to switch at compile time based onconstexpr
. Of course there would be a way to achieve the goal (for instance by overloading forStaticVector
andStaticMatrix
explicitly), but this would unfortunately diminish our runtime performance, which is of course highly undesirable. To our best knowledge there is currently (C++14) no way to implement the functionality you are asking for without sacrificing runtime performance.As also stated in issue #163 we will revisit the issue as soon as we switch to C++17 and try to enable complete compile time computation. In your particular case, however, there might be a middle way. For your purpose it would be enough if
StaticVector
andStaticMatrix
would haveconstexpr
constructors. Then you would be able to implement the arithmetic operations yourself. If this is a reasonable compromise, we would within the next weeks implement the necessary changes. Would this work for you?Best regards,
Klaus!
-
reporter Hello Klaus!
It seems to me that it would be a great compromise!
It would give me the chance of at least get rid of my
std::array
implementation and fuse the code I have until now. I literally have two implementations of the same algorithms withstd::array
andblaze::StaticMatrix
andblaze::StaticVector
explicitly.Please let me know if I can help, I'll be ready to test it once available anyway!
-
-
assigned issue to
-
assigned issue to
-
- changed status to open
-
Hi Astor!
Commits 84730c0 and 71581c4 equip
StaticVector
andStaticMatrix
withconstexpr
constructors, assignment operators and utility functions. Please give me feedback in case an operation that you expect to beconstexpr
is not yet declared asconstexpr
. I apologize for the long delay,Best regards,
Klaus!
-
reporter - attached test.s
Hi Klaus!
Many thanks for your work. I tested the following code:
#include <blaze/Math.h> template <std::size_t nr, std::size_t nc, typename number=double> constexpr inline blaze::StaticVector<number,nr> operator * (const blaze::StaticMatrix<number,nc,nr> & A,const blaze::StaticVector<number,nc> & x) { blaze::StaticVector<number,nr> res ; for (auto i=0u;i<nr;++i) for (auto j=0u;j<nc;++j) res[i] += A(i,j)*x[j]; return res ; } constexpr auto mymain() { const blaze::StaticVector<double,4> x{1.,2.,3.,4.}; const blaze::StaticMatrix<double,4,4> A{{1.,2.,3.,4.}, {5.,6.,7.,8.}, {9.,10.,11.,12.}, {13.,14.,15.,16.}}; const blaze::StaticVector<double,4> res = A*x; return res ; } int main(int argc, char *argv[]) { const volatile auto res = mymain(); return 0; }
Please find the generated assembly attached.
It does generate the solution vector at compile time in data section
.LC0
. However, I had to manually make the copy constructorconstexpr
inblaze/math/dense/StaticVector.h
. I guess there was an interaction with the rest of the code that made it impossible to qualify itconstexpr
?I am also getting A LOT of code related to the generation of random data that I am not using (as far as I am aware). Is that normal?
Thanks again.
Astor
-
Hi Astor!
Thanks for your feedback. The copy constructor is indeed a special case. I'm still running benchmarks to determine if it is possible to improve the runtime performance by explicit vectorization. In that case it unfortunately wouldn't be possible to declare the function
constexpr
since the necessary intrinsics (see the Intel Intrinsics Guide) are notconstexpr
. If I find that compilers perform the vectorization well enough on their own I can also make the copy constructorconstexpr
.As for the amount of generated code I cannot say if this is normal or not. I will have to investigate this as well. Thanks for pointing this out.
Best regards,
Klaus!
-
reporter Thanks for your answer!
I have little hope that GCC will perform the vectorization well enough on its own, just from personal experience. For the moment though, I can work just by changing the copy constructor to
constexpr
myself.The bloating of the executable due to the usage of libraries to generate random numbers is indeed strange though, particularly when I am not using them. I haven't made any measurements yet, but having implemented my code only with STL, then with Eigen and with Blaze, it could be adding a significant amount of compile time. Again, just a hunch.
Thanks a lot!
Astor
-
Hi Astor!
Commits 0684df4 and 8aea9aa add the
constexpr
specifier to the copy constructors and copy assignment operators of theStaticVector
andStaticMatrix
class templates. This hopefully resolves this issue and I apologize for the unusually long delay.As for the code bloat, this seems to be a more general issue that we will deal with separately.
Best regards,
Klaus!
-
- changed status to resolved
The feature has been implemented, tested, optimized, and documented as required. It is immediately available via cloning the Blaze repository and will be officially released in Blaze 3.5.
-
reporter Great!! Thank you very much!
- Log in to comment