C ++:如何使用AVX进行初始化来防止默认构造函数

问题描述 投票:3回答:3

考虑以下:

// foo.h
class Foo
{
   public:
      int x = 2;
      int y = 3;
      void DoSomething_SSE();
      void DoSomething_AVX();
   // ( Implicit default constructor is generated "inline" here )
};

// Foo_AVX.cpp, compiled with -mavx or /arch:AVX
void Foo::DoSomething_AVX()
{
   // AVX optimised implementation here
}

// Foo_SSE.cpp, compiled with -msse2 or /arch:SSE2
void Foo::DoSomething_SSE()
{
   // SSE optimised implementation here
}

这就是问题:编译器将在每个转换单元中生成带有“内联”语义的隐含默认构造函数(注意:内联语义并不意味着函数必然会内联),并且 - 在构造函数未内联的情况下 - 链接器然后将选择一个实现并丢弃另一个。

如果链接器选择在AVX编译单元中生成的构造函数,则此代码将在不支持AVX的计算机上以非法指令崩溃。

可以通过放置一个显式的默认构造函数来停止崩溃,可以是__forceinline(以确保每个编译单元内联一次),或者在头文件中声明并在编译单元中定义,该编译单元使用最小公分母指令集编译。

但是,肯定有一种方法可以让语言更好地处理这个问题而不是编写虚函数。

(Mac OS X上的llvm-clang ++ 9.x.x / x64)

c++ constructor x86 sse avx
3个回答
2
投票

使用gcc或clang -mavx -fno-implement-inlines编译AVX Translation单元;如果函数不是简单内联,则链接器必须从SSE转换单元中找到符号。


从GCC手册:

-fno-implement-inlines 为节省空间,请不要发出由#pragma implementation控制的内联函数的外联副本。如果在调用它们的任何地方没有内联这些函数,这会导致链接器错误。

Clang也支持这个选项。

这不会禁用任何内联,它只会禁用发出声明为inline或类定义的函数的独立定义。

启用优化后,问题中的小型默认构造函数应该内联(并使用当前函数/编译单元的目标ISA选项),这使得这在大多数情况下无关紧要。但它将确保未优化的构建在非AVX机器上正常工作。


1
投票

看来另一种选择是不使用编译器标志来设置指令集 - 将它们保留为默认值,并仅包含需要增强指令集的函数:

#include Foo.h

// Switch on AVX optimisations for the function where they're needed
#pragma clang attribute push (__attribute__((target("arch=sandybridge"))), apply_to = function)

void Foo::DoSomething_AVX()
{
   // AVX optimised implementation here
}
#pragma clang attribute pop

使用#pragma clang属性push(...),虽然比简单的[[]]__attribute__(())更冗长,但似乎有一个优点,即属性自动应用于从pragma范围内实例化的任何模板代码等。


0
投票

将实现放入一个单独的.cpp文件中,并且一切正常。另一种方法是使这些函数/方法/构造函数内联。第三种方式(依赖于编译器)是将它们设置为“弱引用”属性。

© www.soinside.com 2019 - 2024. All rights reserved.