Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/144.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 没有相应编译器标志的Clang/GCC编译器内部函数_C++_Gcc_Clang_Sse_Intrinsics - Fatal编程技术网

C++ 没有相应编译器标志的Clang/GCC编译器内部函数

C++ 没有相应编译器标志的Clang/GCC编译器内部函数,c++,gcc,clang,sse,intrinsics,C++,Gcc,Clang,Sse,Intrinsics,我知道这里也有类似的问题,但是编译带有不同标志的不同文件在这里是不可接受的解决方案,因为它会很快使代码库复杂化。回答“不,不可能”就行了 在任何版本的Clang或GCC中,是否可以编译SSE 2/3/3S/4.1的内部函数,同时只允许编译器使用SSE指令集进行优化 EDIT:例如,我希望编译器将\u mm\u load\u si128()转换为movdqa,但编译器不得在除此内部函数之外的任何其他位置发出此指令,类似于MSVC编译器的工作方式 EDIT2:我有动态调度程序和多个版本的单个函数,

我知道这里也有类似的问题,但是编译带有不同标志的不同文件在这里是不可接受的解决方案,因为它会很快使代码库复杂化。回答“不,不可能”就行了


在任何版本的Clang或GCC中,是否可以编译SSE 2/3/3S/4.1的内部函数,同时只允许编译器使用SSE指令集进行优化

EDIT:例如,我希望编译器将
\u mm\u load\u si128()
转换为
movdqa
,但编译器不得在除此内部函数之外的任何其他位置发出此指令,类似于MSVC编译器的工作方式

EDIT2:我有动态调度程序和多个版本的单个函数,使用内部函数编写了不同的指令集。使用多个文件将使维护变得更加困难,因为同一版本的代码将跨越多个文件,并且有许多此类函数


EDIT3:请求的源代码示例:或该文件夹中的大多数文件。

除了编译器本身的开关之外,没有其他方法控制用于编译器的指令集。换句话说,没有pragmas或其他特性,只有整个编译器标志

这意味着实现您想要的唯一可行的解决方案是使用-msseX并将您的源代码拆分为多个文件(当然,您可以始终使用各种巧妙的
#include
等将一个文本文件保留为主源代码,并在多个位置包含相同的文件)

当然,编译器的源代码是可用的。我相信GCC和Clang/LLVM的维护人员会很高兴地使用改进了这一点的补丁。但请记住,从“解析源代码”到“发出指令”的过程是相当漫长和复杂的。如果我们这样做会发生什么:

#pragma use_sse=1
void func()
{
   ... some code goes here ... 
}

#pragma use_sse=3
void func2()
{
  ...
  func();
  ...
}
现在,func足够短,可以内联,编译器应该内联它吗?如果是,它应该为func()使用sse1或sse3指令吗

我知道您可能不关心这种困难,但是Clang和GCC的维护者确实需要以某种方式来处理这个问题

编辑: 在声明SSE内部函数(以及许多其他内部函数)的HeaderFile中,一个典型的函数如下所示:

extern __inline __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_add_ss (__m128 __A, __m128 __B)
{
  return (__m128) __builtin_ia32_addss ((__v4sf)__A, (__v4sf)__B);
}
只有在启用了-msse选项后,编译器中才能使用内置的ia32地址。因此,如果您说服编译器在使用-mno sse时仍然允许您使用_mm_add_ss(),它将给您一个错误,因为“uu builtin_ia32_addss未在此范围内声明”(我刚刚尝试过)

改变这种特殊的行为可能不是很难——可能只有少数地方代码“引入内置函数”。但是,我不认为代码中还有其他问题,稍后当涉及到在编译器中实际发出指令时

我在基于Clang的编译器中使用“内置函数”做了一些工作,不幸的是,从“解析器”到“代码生成”涉及几个步骤,其中涉及内置函数

编辑2:

与GCC相比,为Clang解决这个问题更加复杂,因为编译器本身理解SSE指令,所以它在头文件中只包含以下内容:

static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_add_ps(__m128 __a, __m128 __b)
{
  return __a + __b;
}
然后,编译器将知道,要添加两个_m128,它需要生成正确的SSE指令。我刚刚下载了Clang(我在家,我对Clang的研究正在进行中,与SSE没有任何关系,只是一般的内置函数——我对Clang本身并没有做太多的更改,但这足以大致了解内置函数的工作原理)


但是,从您的角度来看,它不是一个内置函数这一事实使情况变得更糟,因为
运算符+
转换要复杂得多。我很确定编译器只是把它变成了一个“添加这两个东西”,然后将它传递给LLVM进行进一步的工作-LLVM将是理解SSE指令等的部分。但出于您的目的,这会使它变得更糟,因为这是一个“内在函数”的事实现在几乎丢失了,编译器处理它就像编写了a+b一样,a和b的副作用是128位长的类型。这使得生成“正确的指令”并将“所有其他”指令保持在不同的SSE级别变得更加复杂。

这里有一种使用gcc的方法,可能是可以接受的。所有源代码都放在一个源文件中。单个源文件分为多个部分。一个部分根据使用的命令行选项生成代码。main()和处理器功能检测等函数将在本节中介绍。另一部分根据目标覆盖杂注生成代码。可以使用目标覆盖值支持的内部函数。只有在处理器功能检测确认存在所需的处理器功能后,才能调用本节中的函数。此示例有一个AVX2代码的覆盖部分。编写针对多个目标优化的函数时,可以使用多个覆盖部分

// temporarily switch target so that all x64 intrinsic functions will be available
#pragma GCC push_options
#pragma GCC target ("arch=core-avx2")
#include <intrin.h>
// restore the target selection
#pragma GCC pop_options

//----------------------------------------------------------------------------
// the following functions will be compiled using default code generation
//----------------------------------------------------------------------------

int dummy1 (int a) {return a;}

//----------------------------------------------------------------------------
// the following functions will be compiled using core-avx2 code generation
// all x64 intrinc functions are available
#pragma GCC push_options
#pragma GCC target ("arch=core-avx2")
//----------------------------------------------------------------------------

static __m256i bitShiftLeft256ymm (__m256i *data, int count)
   {
   __m256i innerCarry, carryOut, rotate;

   innerCarry = _mm256_srli_epi64 (*data, 64 - count);                        // carry outs in bit 0 of each qword
   rotate     = _mm256_permute4x64_epi64 (innerCarry, 0x93);                  // rotate ymm left 64 bits
   innerCarry = _mm256_blend_epi32 (_mm256_setzero_si256 (), rotate, 0xFC);   // clear lower qword
   *data    = _mm256_slli_epi64 (*data, count);                               // shift all qwords left
   *data    = _mm256_or_si256 (*data, innerCarry);                            // propagate carrys from low qwords
   carryOut   = _mm256_xor_si256 (innerCarry, rotate);                        // clear all except lower qword
   return carryOut;
   }

//----------------------------------------------------------------------------
// the following functions will be compiled using default code generation
#pragma GCC pop_options
//----------------------------------------------------------------------------

int main (void)
    {
    return 0;
    }

//----------------------------------------------------------------------------
//临时切换目标,以便所有x64内部函数都可用
#pragma GCC推送选项
#pragma GCC目标(“arch=core-avx2”)
#包括
//恢复目标选择
#pragma GCC pop_选项
//----------------------------------------------------------------------------
//以下函数将使用默认代码生成进行编译
//----------------------------------------------------------------------------
int dummy1(int a){返回a;}
//----------------------------------------------------------------------------
//以下函数将使用core-avx2编译