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++ 如何在C++;03给定它是不透明类型和数组?_C++_Swap_Intrinsics_C++03_Sunstudio - Fatal编程技术网

C++ 如何在C++;03给定它是不透明类型和数组?

C++ 如何在C++;03给定它是不透明类型和数组?,c++,swap,intrinsics,c++03,sunstudio,C++,Swap,Intrinsics,C++03,Sunstudio,交换变量的最佳实践是什么 背景是一个C++03编译器\uuuu m128i是一种不透明类型,与MMX和SSE指令一起使用,它通常是和无符号long-long[2]。C++03不支持交换数组,并且std:swap(\uuuu m128i a,\uuuu m128i b)在编译器下失败 以下是一些相关的问题,但它们并不十分中肯。它们不适用,因为std::vector不可用 通过memcpy进行交换 #include <emmintrin.h> #include <cstr

交换
变量的最佳实践是什么

背景是一个C++03编译器
\uuuu m128i
是一种不透明类型,与MMX和SSE指令一起使用,它通常是和
无符号long-long[2]
。C++03不支持交换数组,并且
std:swap(\uuuu m128i a,\uuuu m128i b)
在编译器下失败


以下是一些相关的问题,但它们并不十分中肯。它们不适用,因为
std::vector
不可用


    • 通过
      memcpy进行交换

      #include <emmintrin.h>
      #include <cstring>
      
      template<class T>
      void memswap(T& a, T& b)
      {
          T t;
          std::memcpy(&t, &a, sizeof(t));
          std::memcpy(&a, &b, sizeof(t));
          std::memcpy(&b, &t, sizeof(t));
      }
      
      int main() {
          __m128i x;
          __m128i y;
          memswap(x, y);
          return 0;
      }
      
      #包括
      #包括
      模板
      无效成员交换(T&a、T&b)
      {
      T;
      std::memcpy(&t,&a,sizeof(t));
      std::memcpy(&a,&b,sizeof(t));
      std::memcpy(&b,&t,sizeof(t));
      }
      int main(){
      __m128ix;
      __m128i-y;
      memswap(x,y);
      返回0;
      }
      
      这听起来不像是最佳实践问题;听起来您需要一个解决办法来解决严重破坏的intrinsic实现。如果
      \uuuM128i tmp=a不编译,这很糟糕



      如果要编写自定义交换函数,请保持简单<代码>\uuum128i
      是一种POD类型,适合于单个向量寄存器。不要做任何会鼓励编译器将其溢出到内存中的事情。有些编译器甚至会为一个微不足道的测试用例生成非常糟糕的代码,甚至gcc/clang也可能会在优化一个复杂的大函数时被memcpy绊倒

      由于编译器阻塞了构造函数,只需使用普通的初始值设定项声明一个tmp变量,并使用
      =
      赋值进行复制。这在任何支持
      \uuuu m128i
      的编译器中都是有效的,并且是一种常见的模式

      对内存中的值进行简单赋值或从中赋值的工作方式类似于
      \u mm\u store\u si128
      /
      \u mm\u load\u si128
      :即,如果在未对齐的地址上使用,则会出现故障。(当然,优化可能会导致加载被折叠到另一条向量指令的内存操作数中,或者根本不会发生存储。)

      使用memswap,您可以得到如下结果

      return1st_memcpy(__m128i, __m128i):        ## ICC13 -O3
          movdqa    XMMWORD PTR [-56+rsp], xmm0
          movdqa    XMMWORD PTR [-40+rsp], xmm1    # spill both
          movaps    xmm2, XMMWORD PTR [-56+rsp]    # reload x
          movaps    XMMWORD PTR [-24+rsp], xmm2    # copy x to tmp
          movaps    xmm0, XMMWORD PTR [-40+rsp]    # reload y
          movaps    XMMWORD PTR [-56+rsp], xmm0    # copy y to x
          movaps    xmm0, XMMWORD PTR [-24+rsp]    # reload tmp
          movaps    XMMWORD PTR [-40+rsp], xmm0    # copy tmp to y
          movdqa    xmm0, XMMWORD PTR [-40+rsp]    # reload y
          ret                                      # return y
      
      这几乎是您可以想象的交换两个寄存器的溢出/重新加载的绝对最大量,因为icc13根本不会在内联
      memcpy
      s之间进行优化,甚至不会记住寄存器中剩下的内容


      交换内存中已有的值 甚至gcc也会使memcpy版本的代码变得更糟糕。它使用64位整数加载/存储而不是128位向量加载/存储进行复制。如果您将要加载向量(存储转发暂停),那么这是非常糟糕的,否则就是糟糕的(更多UOP来做同样的工作)


      如果要编写自定义交换函数,只需使用按值赋值,因为这是
      \uuum128i
      值的最佳选择。gcc确实能够优化memcpy并将值保留在寄存器中(使用一个测试函数,该函数接受两个
      \uuuum128i
      参数并返回一个
      \uuuuum128i
      )。简单的分配不太可能对优化产生负面影响。例如,ICC13没有问题。如果两个值都已在内存中,则在
      \uuu m128i
      上使用
      memswap
      时,即使是gcc也可能出现故障。看看我的答案。谢谢彼得,这就是我一直在寻找的洞察力。最后一个悬而未决的问题:我应该提供一个,还是干脆把它作为一个独立的函数?@jww:最好只调用它
      vecswap
      ,这样您就可以在派生类型上使用它了。(例如)。如果您是专门从事此项工作的,您可能希望为
      \uuuum128i
      \uuuuum128d
      \uuuum128
      \uuuuum256*
      \uuuuum512*
      ,以及其他体系结构的任何SIMD类型进行此项工作。(手臂霓虹灯或w/e),然后它就相当笨重了。我更乐意使用一个不同的函数,我相信它总是很轻,并且优化得很好。如果你确定你只需要几个类型,那么值得考虑专门化。信不信由你,这导致了SunCC下最初的编译问题:
      T=a;a=b;b=t。我必须
      T;t=a,a=b,b=t\uuum128i v=\umm\uadd\uepi32(a,b)也是吗?对于大多数代码,我认为我只是考虑它被破坏了,而不是重写任何重要的代码以获得它的好处。@彼得科德如何<代码> VECWAsP()/<代码>不同于<代码> STD::SWAP-()/COD>?
      
      __m128i test_return2nd(__m128i x, __m128i y) {
          vecswap(x, y);
          return x;
      }
      
          movdqa    xmm0, xmm1
          ret                    # returning the 2nd arg, which was in xmm1
      
      
      __m128i test_return1st(__m128i x, __m128i y) {
          vecswap(x, y);
          return y;
      }
      
          ret                   # returning the first arg, already in xmm0
      
      return1st_memcpy(__m128i, __m128i):        ## ICC13 -O3
          movdqa    XMMWORD PTR [-56+rsp], xmm0
          movdqa    XMMWORD PTR [-40+rsp], xmm1    # spill both
          movaps    xmm2, XMMWORD PTR [-56+rsp]    # reload x
          movaps    XMMWORD PTR [-24+rsp], xmm2    # copy x to tmp
          movaps    xmm0, XMMWORD PTR [-40+rsp]    # reload y
          movaps    XMMWORD PTR [-56+rsp], xmm0    # copy y to x
          movaps    xmm0, XMMWORD PTR [-24+rsp]    # reload tmp
          movaps    XMMWORD PTR [-40+rsp], xmm0    # copy tmp to y
          movdqa    xmm0, XMMWORD PTR [-40+rsp]    # reload y
          ret                                      # return y
      
      // the memcpy version of this compiles badly
      void test_mem(__m128i *x, __m128i *y) {
          vecswap(*x, *y);
      }
          # gcc 5.3 and ICC13 make the same code here, since it's easy to optimize
          movdqa  xmm0, XMMWORD PTR [rdi]
          movdqa  xmm1, XMMWORD PTR [rsi]
          movaps  XMMWORD PTR [rdi], xmm1
          movaps  XMMWORD PTR [rsi], xmm0
          ret
      
      // gcc 5.3 with memswap instead of vecswap.  ICC13 is similar
      test_mem_memcpy(long long __vector(2)*, long long __vector(2)*):
          mov     rax, QWORD PTR [rdi]
          mov     rdx, QWORD PTR [rdi+8]
          mov     r9, QWORD PTR [rsi]
          mov     r10, QWORD PTR [rsi+8]
          mov     QWORD PTR [rdi], r9
          mov     QWORD PTR [rdi+8], r10
          mov     QWORD PTR [rsi], rax
          mov     QWORD PTR [rsi+8], rdx
          ret