相关疑难解决方法(0)

128位到512位寄存器用于什么?

在查看x86/x64架构中的寄存器表之后,我注意到有128,256和512位寄存器的整个部分,我从未见过它们用于汇编或反编译的C/C++代码: XMM(0-15)表示128,YMM(0-15)表示256,ZMM(0-31)512.

做了一些挖后我所收集的是,你必须使用2个64位操作,以一个128位的数字进行的,而不是使用通用的数学,add,sub,mul,div操作.如果是这种情况,那么具有这些扩展寄存器集的用途究竟是什么,是否有任何汇编操作可以用来操作它们?

assembly sse x86-64 simd cpu-registers

7
推荐指数
1
解决办法
645
查看次数

通过SSE4包装器比较字符串

我需要快速比较机器上的两个字符串和SSE4支持.如何在不编写汇编程序插入的情况下执行此操作?

一些包装就像long long bitmask = strcmp(char* a, char* b)是完美的.

c++ sse sse4

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

硬件 SIMD 向量指针和相应类型之间的“reinterpret_cast”是否是未定义的行为?

reinterpret_castafloat*到 a__m256*float通过不同的指针类型访问对象是否合法?

constexpr size_t _m256_float_step_sz = sizeof(__m256) / sizeof(float);
alignas(__m256) float stack_store[100 * _m256_float_step_sz ]{};
__m256& hwvec1 = *reinterpret_cast<__m256*>(&stack_store[0 * _m256_float_step_sz]);

using arr_t = float[_m256_float_step_sz];
arr_t& arr1 = *reinterpret_cast<float(*)[_m256_float_step_sz]>(&hwvec1);
Run Code Online (Sandbox Code Playgroud)

hwvec1arr1依赖undefined behaviors 吗?

它们是否违反了严格的别名规则?[基本.lval]/11

或者只有一种定义的内在方式:

__m256 hwvec2 = _mm256_load_ps(&stack_store[0 * _m256_float_step_sz]);
_mm256_store_ps(&stack_store[1 * _m256_float_step_sz], hwvec2);
Run Code Online (Sandbox Code Playgroud)

神箭

c++ x86 intrinsics undefined-behavior language-lawyer

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

如何使用 SIMD 向量化和/或并行化让编译器为字符串搜索循环输出更快的代码?

我有这个 C:

#include <stddef.h>
size_t findChar(unsigned int length, char*  __attribute__((aligned(16))) restrict string) {
    for (size_t i = 0; i < length; i += 2) {
        if (string[i] == '[' || string[i] == ' ') {
            return i;
        }
    }
    return -1;
}
Run Code Online (Sandbox Code Playgroud)

它检查字符串的所有其他字符并返回字符串的第一个索引,即[or 。使用 x86-64 GCC 10.2 -O3 -march=skylake -mtune=skylake,这是汇编输出:

findChar:
        mov     edi, edi
        test    rdi, rdi
        je      .L4
        xor     eax, eax
.L3:
        movzx   edx, BYTE PTR [rsi+rax]
        cmp     dl, 91
        je      .L1
        cmp     dl, 32
        je …
Run Code Online (Sandbox Code Playgroud)

c assembly simd vectorization compiler-optimization

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

GCC 错误地优化了自定义地址处变量的指针相等测试

优化时,GCC 似乎错误地绕过了#define测试。

首先,我使用我自己的link.ld链接器脚本__foo__在地址处提供一个符号0xFFF实际上是最低位,而不是整个地址):

INCLUDE ./default.ld
__foo__ = 0xFFF;
Run Code Online (Sandbox Code Playgroud)
  • 注意:default.ld为默认链接脚本,通过gcc ... -Wl,-verbose命令结果获取

然后,一个foo.c源文件检查__foo__的地址:

INCLUDE ./default.ld
__foo__ = 0xFFF;
Run Code Online (Sandbox Code Playgroud)

我期待***Expected ***打印消息,这FOO_ADDR_IS_EXPECTED()应该是真的。

使用-O0选项编译,它按预期执行:

$ gcc -Wall -Wextra -Werror foo.c -O0 -o foo_O0 -T link.ld && ./foo_O0
__foo__ at 0x5603f4005fff
FOO_ADDR=0xfff
EXPECTED_ADDR=0xfff
***Expected ***
Run Code Online (Sandbox Code Playgroud)

但是有了-O1选项,它不会:

$ gcc -Wall -Wextra -Werror foo.c -O1 -o foo_O1 -T link.ld && ./foo_O1 …
Run Code Online (Sandbox Code Playgroud)

c optimization x86 gcc x86-64

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

确定数字是否出现在字符串中的最快方法是什么?

这个简单的解决方案迅速涌入我的脑海.

#include <ctype.h>

int digit_exists_in
(
    const char *s
)
{
    while (*s)
    {
        if (isdigit(*s))
        {
            return 1;
        }
        else
        {
            s++;
        }
    }

    return 0;
}

int main(void)
{
    int foundDigit = digit_exists_in("abcdefg9ijklmn");

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

还有什么其他技术可以提高速度?

被搜索的实际字符串是可变长度,字符本身是ASCII,而不是完整的字符集.字符串是NUL终止的.

c string performance

5
推荐指数
4
解决办法
1244
查看次数

魔法位如何改进 glibc 中的 strlen 函数

我正在查看glibc 的 strlen的来源。他们用来magic bits求字符串的长度。有人可以解释一下它是如何工作的吗?谢谢

c glibc strlen

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

为什么在AMD64上对mmap内存的未对齐访问有时会出现段错误?

我有这段代码在AMD64兼容CPU上运行Ubuntu 14.04时会出现段错误:

#include <inttypes.h>
#include <stdlib.h>

#include <sys/mman.h>

int main()
{
  uint32_t sum = 0;
  uint8_t *buffer = mmap(NULL, 1<<18, PROT_READ,
                         MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
  uint16_t *p = (buffer + 1);
  int i;

  for (i=0;i<14;++i) {
    //printf("%d\n", i);
    sum += p[i];
  }

  return sum;
}
Run Code Online (Sandbox Code Playgroud)

如果使用分配内存,则仅此段错误mmap.如果我使用malloc,堆栈上的缓冲区,或全局变量,它不会段错误.

如果我将循环的迭代次数减少到少于14的次数,则不再是段错误.如果我从循环内打印数组索引,它也不再是段错误.

为什么未对齐的内存访问能够访问未对齐地址的CPU上的段错误,为什么只有在这种特定情况下呢?

c gcc mmap x86-64 auto-vectorization

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

_IO_puts 和动态指令计数

我是汇编新手,有一个简单的 C 程序将字符串打印到标准输出。在汇编中,这转化为main调用_IO_Puts. _IO_puts下面给出了以下实现:https: //code.woboq.org/userspace/glibc/libio/ioputs.c.html

int
_IO_puts (const char *str)
{
  int result = EOF;
  size_t len = strlen (str);
  _IO_acquire_lock (stdout);
  if ((_IO_vtable_offset (stdout) != 0
       || _IO_fwide (stdout, -1) == -1)
      && _IO_sputn (stdout, str, len) == len
      && _IO_putc_unlocked ('\n', stdout) != EOF)
    result = MIN (INT_MAX, len + 1);
  _IO_release_lock (stdout);
  return result;
}
Run Code Online (Sandbox Code Playgroud)

我无法弄清楚为什么动态指令的数量会发生变化,有时会随着模拟 MIPS 处理器上字符串长度的增加而减少?

c assembly mips

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

是什么阻止编译器优化手写的 memcmp()?

鉴于:

#include <string.h>

bool test_data(void *data)
{
    return memcmp(data, "abcd", 4) == 0;
}
Run Code Online (Sandbox Code Playgroud)

编译器可以将其优化为:

test_data:
    cmpl    $1684234849, (%rdi)
    sete    %al
    ret
Run Code Online (Sandbox Code Playgroud)

这很好。

但如果我使用我自己的memcmp()(而不是来自<string.h>),编译器无法将其优化为单个cmpl指令。相反,它这样做:

test_data:
    cmpl    $1684234849, (%rdi)
    sete    %al
    ret
Run Code Online (Sandbox Code Playgroud)
test_data:
    cmpb    $97, (%rdi)
    jne     .L5
    cmpb    $98, 1(%rdi)
    jne     .L5
    cmpb    $99, 2(%rdi)
    jne     .L5
    cmpb    $100, 3(%rdi)
    sete    %al
    ret
.L5:
    xorl    %eax, %eax
    ret
Run Code Online (Sandbox Code Playgroud)

链接: https: //godbolt.org/z/Kfhchr45a

  • 是什么阻止编译器进一步优化它?
  • 我是否做了一些阻碍优化的事情?

c optimization assembly x86-64 memcmp

5
推荐指数
2
解决办法
333
查看次数