-5

I have an existing c++ project that compiles fine with msvc, and I'm trying to get it to compile in Visual Studio 2022 with LLVM (clang-cl). At the moment I'm using C++ Language Standard Preview ISO C++23, although I don't think this is necessary and would prefer C++20.

Visual Studio Installer tells me I have "C++ Clang Compiler for Windows (19.1.5)" and "MSBuild support for LLVM (clang-cl) toolset".

The project won't compile, it generates hundreds of compile errors. Some popular ones are:

E0020 identifier "__bf16" is undefined (in avx512bf16intrin.h, avxintrin.h and others)

E0020 the global scope has no "int8_t" (in cstdint, xutility, _msvc_minmax.hpp, and others)

E0020 identifier SETJTMP_FLOAT128 is undefined (in setjtmp.h)

What do I need to do to get over the hump? Surely the answer is simple, and duplicated on SO, but I've been Googling for 3 or 4 hours and evidently have not found the right key words for this issue.


Here's a small example that has most of the same compile errors. I was starting to suspect my issues had a lot to do with Agner's vcl, so I just threw his dispatcher sample code into a new project and hit the compile error jackpot. Note, compared to Agner's precise code I am doing some minor edits of the files instrset.h and instrset_detect.cpp to put clang over MSC. Agner's code has clang below MSC and works fine for compiling in standalone clang, but not in Visual Studio clang. Agner's original instrset.h and instrset_detect.cpp are retained in the vcl_agner subdirectory. If you use them you still get most of the same errors.

https://drive.google.com/file/d/1IElPqwWVvifvLHBj94JmjOptmH9tgIGw/view?usp=drive_link


Here is an example with silly-simple simd code. It will generate all the intellisense compile "errors", but it will compile and run correctly. My real code and the code linked above won't compile, but the fatal build errors are linker errors that don't happen compiling in msvc, only when compiling in clang. So I suppose I should be concentrating on the link errors.

#include <stdio.h>
#include <x86intrin.h>
//#include <immintrin.h>  

//#define SIMD_SIZE_SPN 8
#define SIMD_SIZE_SPN 4
//#define SIMD_SIZE_SPN 2

    int main() {
        
        printf("\nhello ms clang\n");
    
        double xarr[SIMD_SIZE_SPN] = {};
    
    #if SIMD_SIZE_SPN == 8
        __m512d vec1, vec2;
        vec1 = _mm512_setr_pd(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0);
        vec2 = _mm512_setr_pd(8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
        vec1 = _mm512_mul_pd(vec1, vec2);   //8, 14, 18, 20, 20, 18, 14, 8
        _mm512_storeu_pd(xarr, vec1);
    #elif SIMD_SIZE_SPN == 4
        __m256d vec1, vec2;
        vec1 = _mm256_setr_pd(1.0, 2.0, 3.0, 4.0);
        vec2 = _mm256_setr_pd(4.0, 3.0, 2.0, 1.0);
        vec1 = _mm256_mul_pd(vec1, vec2);   //4, 6, 6, 4
        _mm256_storeu_pd(xarr, vec1);
    #else
        __m128d vec1, vec2;
        vec1 = _mm_setr_pd(1.0, 2.0);
        vec2 = _mm_setr_pd(2.0, 1.0);
        vec1 = _mm_mul_pd(vec1, vec2);  //2, 2
        _mm_storeu_pd(xarr, vec1);
    #endif
    
        printf("\nlast = %8.2f \n", xarr[SIMD_SIZE_SPN - 1]);   //8, 4, 2
    
        return 0;
    }
22
  • 1
    Do you get errors if you include the same library headers in a brand-new "Hello World" project that was created to use clang initially? It's possible that your project file has non-standard directory search setup and is finding the wrong version of some header files. Commented Oct 2 at 17:35
  • 2
    Make sure you investigate errors in the order they're listed in the Output window. The Errors window likes to reorder things and discard important explanation following each error. Commented Oct 2 at 17:36
  • 2
    @ThomasMatthews did you mean [mre]? Commented Oct 2 at 18:20
  • 2
    Codes starting with an E are not compiler errors, but comes from Intellisense. You can filter the results to show Build errors only, to get the compiler's take on the code. Commented Oct 2 at 20:06
  • 2
    Actually, I was trying to use minimal reproducible example. :-) Commented Oct 2 at 20:24

1 Answer 1

0

Ok, I finally got my original project to compile successfully. The solution was to just assume that (in clang-cl mode) everything Visual Studio was showing me was either a red herring or a rabbit hole, and poke around on my own. In particular, I had to figure out 2 things (in addition to completely ignoring the horrible-looking intellisense):

1.

With arch:/AVX512, Visual Studio IDE shows that none of the AVX512 macros are defined, so the dispatcher shows default to SSE2. This turns out to be simply wrong: The compiler knows all about the AVX512 and compiles correctly. There are no problems with arch:/AVX2 or arch:/AVX.

2.

With arch:/SSE2, Visual Studio IDE shows that everything is situation normal but when it compiles it kicks the architecture back up to AVX with no warning or reporting. This makes the simd dispatcher code fail at the linking stage since now there are 2 identical sets of AVX symbols instead of 1 SSE2 and 1 AVX. Since the project wouldn't compile, I only figured this out by looking at the object files with dumpbin /SYMBOLS *.obj. My solution was to #define an override for arch:/SSE2 that replaces the usual dispatcher code below.

Now the project compiles with no errors and appears to be working as designed. But it all leaves me with a generally low level of confidence in the Visual Studio clang-cl environment.

Edit: When I finally booted my old SSE4.2 computer and tested for this branch I found that my first solution was crashing. Looking at the asm showed that clang-cl was still compiling to the AVX registers, even for __m128 code. Through yet more trial and error I discovered that clang-cl is not behaving well with __m256 source code compiled under /arch:SSE2 or /arch:SSE4.2. The msvc compiler will allow this without comment, letting the programmer handle it via run-time cpuid branching. Clang-cl seems to be either silently boosting everything to AVX when it compiles at all (under some configs), or failing to compile at all (under other configs). My solution is to not be so lazy: put the __m256 code in a setting that is properly dispatched at compile-time.

With this solved I no longer need to #define dispatcher overrides for SSE2 and SSE4.2. The Visual Studio IDE still won't show what is happening for AVX512, SSE2 and SSE4.2, but the results are correct.

#if defined ( __AVX512VL__ ) && defined ( __AVX512BW__ ) && defined ( __AVX512DQ__ ) && defined ( __AVX512CD__ ) && ( __AVX512F__ )
#define INSTRSET 10
#elif defined ( __AVX512F__ ) || defined ( __AVX512__ )
#define INSTRSET 9
#elif defined ( __AVX2__ )
#define INSTRSET 8
#elif defined ( __AVX__ )
#define INSTRSET 7
#elif defined ( __SSE4_2__ )
#define INSTRSET 6
#elif defined ( __SSE4_1__ )
#define INSTRSET 5
#elif defined ( __SSSE3__ )
#define INSTRSET 4
#elif defined ( __SSE3__ )
#define INSTRSET 3
#elif defined ( __SSE2__ ) || defined ( __x86_64__ )
#define INSTRSET 2
#elif defined ( __SSE__ )
#define INSTRSET 1
#elif defined ( _M_IX86_FP )           // Defined in MS compiler. 1: SSE, 2: SSE2
#define INSTRSET _M_IX86_FP
#else
#define INSTRSET 0
#endif
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.