According to this page https://sourceware.org/glibc/wiki/libmvec, I should be able to manually vectorize a few complicated instructions like cosine by using the libmvec functions. However, I don’t know how to get gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0 to recognize them. Am I missing some compiler flags or something? Any help or suggestions are appreciated.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
#include <immintrin.h>
// gcc libmvectest.c -o libmvectest.bin -lm -O3 -Wall -ffast-math -march=msse4
int main(int argc, char **argv)
{
float input = 0.1;
float res[4];
__m128 m128 = _mm_set1_ps(input);
__m128 cosm128 = _ZGVbN4ua16vl_cosf(m128);
_mm_storeu_ps(res, cosm128);
printf("%.8f %.8fn", cosf(input), res[0]);
}
I’ve googled the ‘implicit declaration…’ error for the prefixed functions but failed to find an answer that worked for me. I tried _ZGVbN4ua16vl_cos, _ZGVbN4ua16vl_cosf and other attempts. Does anyone know where the actual function names are listed?
3
Answers
Thanks to all who looked into this. The main point of the question was to manually vectorize using those built in functions so as to not rely on the optimiser which can easily get confused if you're doing more than just a simple one function loop. The suggestion by Peter Cordes worked on my system so this code now compiles and runs successfully.
The implicit declaration error is what you get when you use a function name that doesn’t exist in any of your include files (or anything included by them).
As far as I understand from the article, the libmvec is an alternative implementation, but the functions themselves are coming from math.h,
so you should keep calling the existing cos() and sin() functions.
The name you specified (_ZGVbN4ua16vl_cosf) is not something you should call directly but an internal vectorized alternative that will replace the loop in your code (I must admit I have no idea how that works, but this is the optimizer’s work)
If you did so well, the compiler / optimizer would automatically bring in the optimized (vectorized) version of the math function.
here is a way to see that:
Let’s take the following code from the article (Link to article)
name this file
test_math.c
.now, if you compile it normally:
gcc ./test_math.c -lm
You can now use the nm command (which lists all symbols in a binary file) to check which sin symbols are compiled:
The "U" hints that a symbol exists in the code but is undefined, this is because the binary file uses dynamic linking to the math library and it will be provided only when the binary file is running.
Now, you can compile the same file but this time using the optimizations (which implicitly brings in the libmvec library), and check again:
Now you see that the binary file a.out is using the _ZGVcN4v_sin which is the optimized (vectorized) variant function. although you didn’t mention it in the code.
Another tip, if you are using linux and just want to know how to use a math function you can just run the following command (as an example):
#man sin
This is just a snippet from the output, but you can see the the manual section you are reading is marked as SIN(3). The "3" means that this is a documentation of the LibC you are using.
You can also see which include file to use and how to link the library. (add -lm to your compilation command)
Those OpenMP-SIMD clones are not intended to be invoked by hand from portable C. They are not declared as separate functions; instead, they are introduced as multiple variants of a standard function via
#pragma omp declare simd
or__attribute__((simd))
for use by automatic vectorization. On a Glibc-based system you can inspect the declarations in/usr/include/bits/math-vector.h
.For use in explicitly vectorized code you can write simple wrappers with a trivially vectorizable loop like this:
which
gcc -O2 -ftree-vectorize
is able to optimize tohttps://godbolt.org/z/jdfeoT7K5