未解决的外部符号__mm256_setr_epi64x

5
我已经使用g++编写和调试了一些AVX代码,现在我正在尝试让它与MSVC一起工作,但是我一直收到以下错误:
“error LNK2019:在函数“private: union __m256i __thiscall avx_matrix::avx_bit_mask(unsigned int)const ”(?avx_bit_mask@avx_matrix@@ABE?AT__m256i@@I@Z)中引用的未解析的外部符号__mm256_setr_epi64x”
所引用的代码片段为:
...

#include <immintrin.h>

...

    /* All zeros except for pos-th position (0..255) */
    __m256i avx_matrix::avx_bit_mask(const std::size_t pos) const
    {
        int64_t a = (pos >= 0 && pos < 64) ? 1LL << (pos - 0) : 0;
        int64_t b = (pos >= 64 && pos < 128) ? 1LL << (pos - 64) : 0;
        int64_t c = (pos >= 128 && pos < 192) ? 1LL << (pos - 128) : 0;
        int64_t d = (pos >= 192 && pos < 256) ? 1LL << (pos - 256) : 0;
        return _mm256_setr_epi64x(a, b, c, d);
    }
...
  • 我已启用 /arch:AVX,但是没有任何区别。
  • 我的机器确实支持 AVX - 它与我用于原始 Linux 项目的机器相同。
  • 另外,http://msdn.microsoft.com/en-us/library/hh977022.aspx 列出了可用 Intrinsic 函数之一是 _mm256_setr_epi64x

非常感谢您的帮助。

2个回答

5

看起来这可能是一个已知的错误 - 某些AVX内部函数在32位模式下显然不可用。尝试构建64位和/或升级到Visual Studio 2013 Update 2,据说这个问题现在已经被修复。

或者,如果您只有上面使用该内部函数的一个实例,那么您可以将函数更改为:

__m256i avx_matrix::avx_bit_mask(const std::size_t pos) const
{
    int64_t a[4] = { (pos >=   0 && pos <  64) ? 1LL << (pos -   0) : 0,
                     (pos >=  64 && pos < 128) ? 1LL << (pos -  64) : 0,
                     (pos >= 128 && pos < 192) ? 1LL << (pos - 128) : 0,
                     (pos >= 192 && pos < 256) ? 1LL << (pos - 256) : 0 };
    return _mm256_loadu_si256((__m256i *)a);
}

或者甚至可能是:

__m256i avx_matrix::avx_bit_mask(const std::size_t pos) const
{
    int64_t a[4] = { 0 };
    a[pos >> 6] = 1LL << (pos & 63ULL);
    return _mm256_loadu_si256((__m256i *)a);
}

这可能会更有效率。


2
嘿 - 看起来微软忘记更新他们的证书了。 - Paul R
1
找到这个问题已经被修复,加一分。但是,现在已经是2014年了,还有谁会使用32位模式呢?OS X现在只支持64位。Ubuntu将在一年内逐步淘汰32位。微软应该在8年前就解决这个问题了。 - Z boson
1
人们通常因为各种原因而被困在 Windows 的 32 位系统上:第三方仅支持 32 位的库、使用内联汇编器、不支持 64 位的旧代码等等。但这只是我尽可能避免整个有毒的 Microsoft 生态系统的众多原因之一 - 我会坚持使用 OS X 和 Linux,谢谢。 - Paul R
1
我几个月前就放弃了MSVC。它在优化方面并不是很出色,而且喜欢做太多不同的事情,例如它只定义了__AVX____AVX2__。它只支持2003年的OpenMP。当我将我的分形代码转换为使用FMA时,MSVC比不使用FMA要慢得多。而在GCC中,它则更快。 - Z boson
2
你使用 _mm256_loadu_si256 的解决方案显然比我的好。我没有仔细考虑过这个问题。当然,我永远不会在主循环中使用我的解决方案。我专注于内部函数。如果这个问题问如何高效地设置单个位给定索引,那么它会更好。 - Z boson
显示剩余3条评论

5
在32位模式下MSVC不支持以下函数:
  • _mm_set_epi64x
  • _mm_setr_epi64x
  • _mm_set1_epi64x
  • _mm256_set_epi64x
  • _mm256_setr_epi64x
  • _mm256_set1_epi64x
在32位模式下您可以这样做:
    union {
        int64_t q[4];
        int32_t r[8];
    } u;
    u.q[0] = a; u.q[1] = b; u.q[2] = c; u.q[3] = d;
    return _mm256_setr_epi32(u.r[0], u.r[1], u.r[2], u.r[3], u.r[4], u.r[5], u.r[6], u.r[7]);

自Visual Studio 2015(_MSC_VER 1900)起,这些内置函数在32位模式下得到支持。

我认为你在使用联合体的方式是C++中未定义的行为。 - jww
1
如何访问未激活的联合成员以及未定义的行为? - jww
@jww,我阅读了链接中的一些答案,但我感到困惑。如果您认为有其他非UB的解决方案,请随意补充我的回答(请勿删除任何内容,只需在我现有的回答后添加新信息)。 - Z boson
@jww,我猜使用memcpy是一种更安全(但更低效)的解决方案? - Z boson
我非常确定所有主要的编译器都明确支持C++中的C风格联合类型转换,即使在C++中它在技术上是未定义的。 - Mysticial
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接