在查看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操作.如果是这种情况,那么具有这些扩展寄存器集的用途究竟是什么,是否有任何汇编操作可以用来操作它们?
我需要快速比较机器上的两个字符串和SSE4支持.如何在不编写汇编程序插入的情况下执行此操作?
一些包装就像long long bitmask = strcmp(char* a, char* b)是完美的.
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)
做hwvec1和arr1依赖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:
#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) 优化时,GCC 似乎错误地绕过了#define测试。
首先,我使用我自己的link.ld链接器脚本__foo__在地址处提供一个符号0xFFF(实际上是最低位,而不是整个地址):
INCLUDE ./default.ld
__foo__ = 0xFFF;
Run Code Online (Sandbox Code Playgroud)
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) 这个简单的解决方案迅速涌入我的脑海.
#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终止的.
我正在查看glibc 的 strlen的来源。他们用来magic bits求字符串的长度。有人可以解释一下它是如何工作的吗?谢谢
我有这段代码在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 程序将字符串打印到标准输出。在汇编中,这转化为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 处理器上字符串长度的增加而减少?
鉴于:
#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