相关疑难解决方法(0)

为什么SSE标量sqrt(x)比rsqrt(x)*x慢?

我一直在英特尔Core Duo上分析我们的一些核心数学,并且在研究平方根的各种方法时,我注意到一些奇怪的事情:使用SSE标量操作,采用倒数平方根并乘以它更快获取sqrt,而不是使用本机sqrt操作码!

我正在测试它的循环类似于:

inline float TestSqrtFunction( float in );

void TestFunc()
{
  #define ARRAYSIZE 4096
  #define NUMITERS 16386
  float flIn[ ARRAYSIZE ]; // filled with random numbers ( 0 .. 2^22 )
  float flOut [ ARRAYSIZE ]; // filled with 0 to force fetch into L1 cache

  cyclecounter.Start();
  for ( int i = 0 ; i < NUMITERS ; ++i )
    for ( int j = 0 ; j < ARRAYSIZE ; ++j )
    {
       flOut[j] = TestSqrtFunction( flIn[j] ); …
Run Code Online (Sandbox Code Playgroud)

floating-point performance x86 assembly sse

106
推荐指数
4
解决办法
4万
查看次数

是否通过C99中未指定的联合进行类型惩罚,并且它是否在C11中指定?

Stack Overflow问题的一些答案获取浮点数的IEEE单精度位建议使用union类型双关的结构(例如:将a的位float转换为a uint32_t):

union {
    float f;
    uint32_t u;
} un;
un.f = your_float;
uint32_t target = un.u;
Run Code Online (Sandbox Code Playgroud)

但是,uint32_t根据C99标准(至少草案n1124),联盟成员的值似乎未指定,其中第6.2.6.1.7节规定:

当值存储在union类型的对象的成员中时,对象表示的字节与该成员不对应但与其他成员对应的字节采用未指定的值.

C11 n1570草案至少有一个脚注似乎暗示不再是这种情况(见6.5.2.3中的脚注95):

如果用于读取union对象的内容的成员与上次用于在对象中存储值的成员不同,则将值的对象表示的适当部分重新解释为新类型中的对象表示形式在6.2.6中描述(一个过程有时被称为''punning'').这可能是陷阱表示.

但是,第C.6.6.1.7节中的案文与C11草案中的C99草案相同.

这种行为在C99下实际上是未指定的吗?它是否在C11中指定?我意识到大多数编译器似乎都支持这一点,但是知道它是在标准中指定还是只是一个非常常见的扩展会很好.

c c99 unions type-punning c11

58
推荐指数
3
解决办法
8770
查看次数

26
推荐指数
2
解决办法
2万
查看次数

在实践中,工会,别名和打字:什么有效,有什么不可行?

我有一个问题,了解使用GCC的工会可以做什么和不可以做什么.我阅读了有关它的问题(特别是这里这里),但他们关注C++标准,我觉得C++标准和实践(常用的编译器)之间存在不匹配.

特别是,我最近在阅读有关编译标志-fstrict-aliasingGCC在线文档中发现了令人困惑的信息.它说:

-fstrict走样

允许编译器采用适用于正在编译的语言的最严格的别名规则.对于C(和C++),这将根据表达式的类型激活优化.特别地,假设一种类型的对象永远不会与不同类型的对象驻留在相同的地址,除非类型几乎相同.例如,a unsigned intcan可以是a int,但不是a void*或a double.字符类型可以别名为任何其他类型.特别注意这样的代码:

union a_union {
  int i;
  double d;
};

int f() {
  union a_union t;
  t.d = 3.0;
  return t.i;
}
Run Code Online (Sandbox Code Playgroud)

从不同的工会成员阅读的做法比最近写的那个(称为"打字式")很常见.即使使用-fstrict-aliasing,只要通过union类型访问内存,就允许类型为punning.因此,上面的代码按预期工作.

这是我认为我从这个例子和我的疑虑中理解的:

1)别名仅适用于相似类型或char

1)的后果:别名 - 正如文字暗示的那样 - 是你有一个值和两个成员来访问它(即相同的字节);

怀疑:当它们具有相同的字节大小时,两种类型是相似的吗?如果没有,什么是类似的类型?

1)对于非相似类型(无论这意味着什么)的后果,别名不起作用;

2)类型双关语是指我们读的不同于我们写的成员; 它是常见的,只要通过union类型访问内存,它就可以正常工作;

怀疑:在类型相似的特定情况下别名是什么类型?

我感到困惑,因为它表示unsigned int和double不相似,所以别名不起作用; 然后在示例中它是int和double之间的别名,它清楚地表明它按预期工作,但称之为类型 - 惩罚:不是因为类型是或不相似,而是因为它是从一个不写的成员读取.但是从一个没有写的成员那里读取的是我所理解的混淆(正如这个词所暗示的那样).我迷路了.

问题: 有人可以澄清别名和类型惩罚之间的区别,这两种技术的用途是如何在GCC中发挥作用的?编译器标志有什么作用?

c++ gcc strict-aliasing

16
推荐指数
2
解决办法
1374
查看次数

如何在没有编译器浪费指令归零上层元素的情况下将标量合并到向量中?英特尔内在函数的设计限制?

我没有特定的用例; 我问这是否真的是英特尔内在函数中的设计缺陷/限制,或者我是否只是遗漏了某些内容.

如果你想将标量浮点数与现有向量相结合,那么在没有高元素归零或使用英特尔内在函数将标量广播到向量中的情况下似乎没有办法实现.我没有研究过GNU C本机向量扩展和相关的内置函数.

如果额外的内在优化了,这不会太糟糕,但它不与gcc(5.4或6.2).也没有好的方法可以使用pmovzxinsertps作为负载,因为他们的内在函数只采用向量args的相关原因.(并且gcc不会将标量 - >向量加载到asm指令中.)

__m128 replace_lower_two_elements(__m128 v, float x) {
  __m128 xv = _mm_set_ss(x);        // WANTED: something else for this step, some compilers actually compile this to a separate insn
  return _mm_shuffle_ps(v, xv, 0);  // lower 2 elements are both x, and the garbage is gone
}
Run Code Online (Sandbox Code Playgroud)

gcc 5.3 -march = nehalem -O3输出,启用SSE4.1并调整该Intel CPU :(没有SSE4.1会更糟;多个指令将上层元素归零).

    insertps  xmm1, xmm1, 0xe    # pointless zeroing of upper elements.  shufps only reads the low element of xmm1 …
Run Code Online (Sandbox Code Playgroud)

c x86 gcc sse intrinsics

8
推荐指数
1
解决办法
601
查看次数

在AVX2中高效实现log2(__ m256d)

__m256d _mm256_log2_pd (__m256d a)除了英特尔之外,SVML 还没有其他编译器可用,他们表示其性能在AMD处理器上是有缺陷的.在g ++ - 4.8中缺少AVX日志内在函数(_mm256_log_ps)中的一些互联网实现SSE和AVX的SIMD数学库,但它们似乎比AVX2更多的SSE.还有Agner Fog的矢量库,但是它是一个包含更多东西的大型库,它只是向量log2,所以从它的实现中很难找出向量log2操作的基本部分.

那么有人可以解释如何有效地实现log2()4个double数字向量的操作吗?即就是__m256d _mm256_log2_pd (__m256d a)这样,但可用于其他编译器,并且AMD和Intel处理器的效率相当高.

编辑:在我目前的特定情况下,数字是介于0和1之间的概率,而对数用于熵计算:所有i的和的否定P[i]*log(P[i]).浮点指数的P[i]范围很大,因此数字可以接近0.我不确定准确度,因此会考虑以30位尾数开头的任何解决方案,尤其是可调整的解决方案.

EDIT2:这是我到目前为止的实现,基于https://en.wikipedia.org/wiki/Logarithm#Power_series的 "更有效的系列" .怎么改进?(需要提高性能和精度)

namespace {
  const __m256i gDoubleExpMask = _mm256_set1_epi64x(0x7ffULL << 52);
  const __m256i gDoubleExp0 = _mm256_set1_epi64x(1023ULL << 52);
  const __m256i gTo32bitExp = _mm256_set_epi32(0, 0, 0, 0, 6, 4, 2, 0);
  const __m128i gExpNormalizer = _mm_set1_epi32(1023);
  //TODO: some 128-bit variable or two 64-bit variables …
Run Code Online (Sandbox Code Playgroud)

c++ algorithm floating-point logarithm avx2

7
推荐指数
2
解决办法
1636
查看次数