小编Yal*_*ang的帖子

将32位偏移量添加到x86-64 ABI的指针时是否需要符号或零扩展?

简介:我正在查看汇编代码来指导我的优化,并在将int32添加到指针时看到许多符号或零扩展.

void Test(int *out, int offset)
{
    out[offset] = 1;
}
-------------------------------------
movslq  %esi, %rsi
movl    $1, (%rdi,%rsi,4)
ret
Run Code Online (Sandbox Code Playgroud)

起初,我认为我的编译器在添加32位到64位整数时遇到了挑战,但我已经用Intel ICC 11,ICC 14和GCC 5.3证实了这种行为.

这个帖子证实了我的发现,但不清楚是否需要符号或零扩展.仅当尚未设置高32位时,才需要此符号/零扩展.但x86-64 ABI难道不够聪明吗?

我有点不愿意将所有指针偏移更改为ssize_t,因为寄存器溢出会增加代码的缓存占用空间.

assembly x86-64 abi compiler-optimization sign-extension

16
推荐指数
1
解决办法
2591
查看次数

接近log10 [x ^ k0 + k1]

问候.我正在尝试近似函数

Log10 [x ^ k0 + k1],其中.21 <k0 <21,0 <k1 <~2000,并且x是整数<2 ^ 14.

k0和k1是不变的.出于实际目的,可以假设k0 = 2.12,k1 = 2660.期望的精度是5*10 ^ -4相对误差.

这个函数实际上与Log [x]相同,除了0附近,它有很大的不同.

我已经提出了一个比简单查找表快1.15倍的SIMD实现,但是如果可能的话我想改进它,我认为由于缺乏有效的指令而非常困难.

我的SIMD实现使用16位定点算法来评估三次多项式(我使用最小二乘拟合).多项式对不同的输入范围使用不同的系数.有8个范围,范围i跨越(64)2 ^ i到(64)2 ^(i + 1).这背后的理性是Log [x]的导数随x快速下降,这意味着多项式将更准确地拟合它,因为多项式非常适合于具有超出某个阶的0的导数的函数.

使用单个_mm_shuffle_epi8()可以非常有效地完成SIMD表查找.我使用SSE的float到int转换来获得指数和有效数,用于固定点近似.我还通过软件管道化循环以获得~1.25倍的加速,因此可能不太可能进行进一步的代码优化.

我要问的是,如果在更高的水平上有更高效的近似值?例如:

  1. 可以将此函数分解为具有有限域的函数,如log2((2 ^ x)*significand)= x + log2(有效数字)

因此消除了处理不同范围(表查找)的需要.我认为的主要问题是添加k1术语会杀死我们所知道和喜爱的所有那些不错的日志属性,这使得它无法实现.或者是吗?

  1. 迭代方法?不要这么认为,因为log [x]的牛顿方法已经是一个复杂的表达式

  2. 利用邻近像素的局部性? - 如果8个输入的范围落在相同的近似范围内,那么我可以查找单个系数,而不是查找每个元素的单独系数.因此,我可以将其用作快速常见的情况,并在不使用时使用较慢的通用代码路径.但是对于我的数据,在该属性保持70%的时间之前,范围需要大约2000,这似乎不会使这种方法具有竞争力.

请给我一些意见,特别是如果你是一名应用数学家,即使你说它不能完成.谢谢.

math optimization sse simd approximation

11
推荐指数
1
解决办法
1091
查看次数

将散点索引转换为聚集索引的有效方法?

我正在尝试使用SIMD内在函数编写流压缩(获取数组并删除空元素).循环的每次迭代一次处理8个元素(SIMD宽度).

使用SSE内在函数,我可以使用_mm_shuffle_epi8()进行相当有效的操作,它执行16条表查找(收集并行计算术语).shuffle索引是预先计算的,并使用位掩码查找.

for (i = 0; i < n; i += 8)
{
  v8n_Data = _mm_load_si128(&data[i]);
  mask = _mm_movemask_epi8(&is_valid[i]) & 0xff;     // is_valid is byte array
  v8n_Compacted = _mm_shuffle_epi8(v16n_ShuffleIndices[mask]);
  _mm_storeu_si128(&compacted[count], v8n_Compacted);

  count += bitCount[mask];
}
Run Code Online (Sandbox Code Playgroud)

我的问题是现在我想为Altivec SIMD实现这个(不要问为什么 - 错误的商业决策).Altivec没有_mm_movemask_epi8()的等价物,这是一个关键因素.所以,我需要找到一种方法

  1. 模拟_mm_movemask_epi8() - 似乎很贵,有几个班次和OR

  2. 直接生成有效的shuffle指数 -

即,索引i将是未压缩数据中第i个有效元素的索引

element_valid:   0 0 1 0 1 0 0 1 0
gather_indices:  x x x x x x 6 4 1
scatter_indices: 3 3 2 2 1 1 1 0 0
Run Code Online (Sandbox Code Playgroud)

串行执行此操作非常简单,但我需要它是并行(SIMD).使用前缀sum生成散列索引似乎很容易,但由于AltiVec和SSE都没有散点指令,我需要收集索引.收集索引是散射指数的反函数,但是如何并行获得?我知道在GPU编程的开创性时代,将散射转换为收集是一种常见的技术,但这两种方法中没有一种看似实用.

也许如果不坚持压缩保留元素顺序将允许更有效的实现?我可以放弃.

sse simd vectorization altivec stream-compaction

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

为什么for循环有一个超出预期的额外指令?

我写了很多矢量化循环,所以有一个常见的习语

volatile int dummy[1<<10];
for (int64_t i = 0; i + 16 <= argc; i+= 16)   // process all elements with whole vector
{
  int x = dummy[i];
}
// handle remainder (hopefully with SIMD too)
Run Code Online (Sandbox Code Playgroud)

但是生成的机器代码比我想要的多1个指令(使用gcc 4.9)

.L3:
        leaq    -16(%rax), %rdx
        addq    $16, %rax
        cmpq    %rcx, %rax
        movl    -120(%rsp,%rdx,4), %edx
        jbe     .L3
Run Code Online (Sandbox Code Playgroud)

如果我将代码更改为for (int64_t i = 0; i <= argc - 16; i+= 16),则"额外"指令消失了:

.L2:
        movl    -120(%rsp,%rax,4), %ecx
        addq    $16, %rax
        cmpq    %rdx, %rax
        jbe     .L2
Run Code Online (Sandbox Code Playgroud)

但为什么差异呢?我想也许这是由于循环不变量,但是太模糊了.然后我注意到在5指令的情况下,增量在加载之前完成,由于x86的破坏性2操作数指令,这将需要额外的mov.所以另一种解释可能是它为一条额外的指令交易指令并行性. …

optimization x86 assembly gcc gcc4.9

6
推荐指数
1
解决办法
130
查看次数

循环变量类型在用于索引数组时会影响效率吗?

我正在尝试将代码优化到最后一个可能的循环,并且想知道循环类型在用于数组索引时是否会影响性能?

我用以下程序做了一些实验,只用0填充数组:

int main(int argc, char **argv)
{
  typedef int CounterType;
  typedef int64_t CounterType;

  CounterType N = atoi(argv[1]);
  uint8_t volatile dummy[N + 16];
  __m128i v = _mm_set1_epi8(0);
  for (int j = 0; j < 1000000; ++j)
  {
    #pragma nounroll
    for (CounterType i = 0; i <= N; i+= CounterType(16))
    {
        _mm_storeu_si128((__m128i *)&dummy[i], v);
    }
  }
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

通过使用不同的循环计数器类型(CounterType)和不同的编译器,我使用硬件性能计数器("perf stat a.out 32768")记录了内循环的汇编代码和性能.我在Xeon 5670上运行.

GCC4.9,int

.L3
movups  %xmm0, (%rax)
addq    $16, %rax
movl    %eax, %edx
subl    %esi, %edx
cmpl    %ecx, %edx …
Run Code Online (Sandbox Code Playgroud)

c optimization performance x86 assembly

5
推荐指数
1
解决办法
221
查看次数

在构建具有共同依赖项的目标时,GNU make 是否会受到竞争条件的影响?

我有一个简单的示例 makefile 来显示我的问题:

.PHONY: a.out b.out

all: a.out b.out

common:
    echo building common
    sleep 1
    touch common

a.out: common
    echo building a.out
b.out: common
    echo building b.out
Run Code Online (Sandbox Code Playgroud)

a.out & b.out 取决于 common,因此在进行并行构建时可能会出现竞争条件(common 生成两次)。

我确实 make -j4 并且没有遇到 common 被生成两次。我什至在 common 生成中添加了 sleep 语句,以使事情更具确定性。

那么可以说 GNU make 在构建公共依赖项时正确同步吗?

makefile gnu-make race-condition

3
推荐指数
1
解决办法
1508
查看次数