除了编译器本身的开关之外,没有办法控制编译器使用的指令集。换句话说,没有任何编译指示或其他功能,只有整体编译器标志。
这意味着实现您想要的唯一可行解决方案是使用 -msseX 并将源代码拆分成多个文件(当然,您始终可以使用各种巧妙的 #include 等方法将一个单独的文本文件作为主源,并在多个位置包含相同的文件)
当然,编译器的源代码是可用的。我相信 GCC 和 Clang/LLVM 的维护者会很乐意接受改进此问题的补丁。但请记住,“解析源代码”到“发出指令”的路径非常漫长和复杂。如果我们这样做会发生什么:
void func()
{
... some code goes here ...
}
void func2()
{
...
func();
...
}
现在,func函数足够短,可以内联,编译器应该内联它吗?如果是这样,对于func(),它应该使用sse1还是sse3指令。
我知道你可能不关心这种困难,但是Clang和GCC的维护者确实需要以某种方式处理这个问题。
编辑:
在声明SSE内部函数(以及许多其他内部函数)的头文件中,典型的函数看起来像这样:
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)
}
builtin_ia32_addss只有在启用-msse选项时编译器才可用。因此,如果您说服编译器在-mno-sse时仍允许您使用_mm_add_ss(),它将为“__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的更改,但足以大致了解内置函数的工作原理)。
然而,从您的角度来看,它不是内置函数使情况变得更糟,因为operator+的转换更加复杂。我相信编译器只会将其转换为“将这两个东西相加”,然后将其传递给LLVM进行进一步处理 - LLVM将是理解SSE指令等部分的组成部分。但对于您的目的而言,这使情况变得更糟,因为这是一个“内部函数”的事实现在几乎已经丢失了,编译器处理它的方式就像您编写了a + b一样,具有a和b长度为128位的类型副作用。这使得生成“正确的指令”并保持“所有其他”指令处于不同的SSE级别变得更加复杂。
-mtune=native
标志来编译gcc
。你同意吗?你可能想要在构建器方面投入更多的努力(例如为最新版本的make
编写复杂的Makefile
)。 - Basile Starynkevitch