skip to Main Content

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


  1. Chosen as BEST ANSWER

    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.

    #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
    
    extern __m128  _ZGVbN4v_cosf(__m128);
    
    int main(int argc, char **argv)
    {
      float input = 0.1;
      float res[4];
      __m128  m128 = _mm_set1_ps(input);
      __m128  cosm128 = _ZGVbN4v_cosf(m128);
      _mm_storeu_ps(res, cosm128);
      printf("%.8f %.8fn", cosf(input), res[0]);
    }
    

  2. 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)

    #include <math.h>
    
    int N = 3200;
    double b[3200];
    double a[3200];
    
    int main (void)
    {
      int i;
    
      for (i = 0; i < N; i += 1)
      {
        b[i] = sin (a[i]);
      }
    
      return (0);
    }
    

    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:

    #nm -a a.out  | grep sin
    
      U sin@@GLIBC_2.2.5
    

    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:

    #gcc ./test_math.c -O1 -ftree-loop-vectorize -ffast-math -lm -mavx
    #nm -a a.out  | grep sin
                     U _ZGVcN4v_sin@@GLIBC_2.22
                     U sin@@GLIBC_2.2.5
    
    

    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

    SIN(3)                                        Linux Programmer's Manual                                        
    
    NAME
           sin, sinf, sinl - sine function
    
    SYNOPSIS
           #include <math.h>
    
           double sin(double x);
           float sinf(float x);
           long double sinl(long double x);
    
           Link with -lm.
    

    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)

    Login or Signup to reply.
  3. 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:

    #include <immintrin.h>
    
    __attribute__((simd("notinbranch")))
    float cosf(float);
    
    __m128 t(__m128 x)
    {
        for (int i = 0; i < sizeof x / sizeof x[0]; i++)
            x[i] = cosf(x[i]);
        return x;
    }
    

    which gcc -O2 -ftree-vectorize is able to optimize to

    t:
            jmp     _ZGVbN4v_cosf
    

    https://godbolt.org/z/jdfeoT7K5

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search