在x86-64 Tour of Intel Manuals中,我读到了
也许最令人惊讶的事实是,诸如
MOV EAX, EBX自动将指令的高32位归零的指令RAX.
同一来源引用的英特尔文档(3.4.1.1 64位手动基本架构中的通用寄存器)告诉我们:
- 64位操作数在目标通用寄存器中生成64位结果.
- 32位操作数生成32位结果,在目标通用寄存器中零扩展为64位结果.
- 8位和16位操作数生成8位或16位结果.目标通用寄存器的高56位或48位(分别)不会被操作修改.如果8位或16位操作的结果用于64位地址计算,则将寄存器显式符号扩展为完整的64位.
在x86-32和x86-64汇编中,16位指令如
mov ax, bx
Run Code Online (Sandbox Code Playgroud)
不要表现出这种"奇怪"的行为,即eax的上层词被归零.
因此:引入这种行为的原因是什么?乍一看似乎不合逻辑(但原因可能是我习惯了x86-32汇编的怪癖).
说到C++的并发内存模型,Stroustrup的C++编程语言,第4版,第1节.41.2.1,说:
...(像大多数现代硬件一样)机器无法加载或存储任何小于单词的东西.
但是,我的x86处理器,几年前,可以存储小于一个字的对象.例如:
#include <iostream>
int main()
{
char a = 5;
char b = 25;
a = b;
std::cout << int(a) << "\n";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果没有优化,GCC将其编译为:
[...]
movb $5, -1(%rbp) # a = 5, one byte
movb $25, -2(%rbp) # b = 25, one byte
movzbl -2(%rbp), %eax # load b, one byte, not extending the sign
movb %al, -1(%rbp) # a = b, one byte
[...]
Run Code Online (Sandbox Code Playgroud)
评论是由我提出的,但是汇编是由GCC提出的.当然,它运行良好.
显然,我不明白Stroustrup在谈到硬件可以加载和存储任何小于一个单词的内容时所说的内容.据我所知,我的计划什么也不做,但加载和存储对象小于一个字的.
C++对零成本,硬件友好的抽象的彻底关注使C++与其他易于掌握的编程语言区别开来.因此,如果Stroustrup在公交车上有一个有趣的信号心理模型,或者有其他类似的东西,那么我想了解Stroustrup的模型.
什么是 Stroustrup谈论,拜托?
更长时间的背景声明 …
简介:我正在查看汇编代码来指导我的优化,并在将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,因为寄存器溢出会增加代码的缓存占用空间.
write(1,"hi",3)在linux上反汇编,gcc -s -nostdlib -nostartfiles -O3结果如下:
ba03000000 mov edx, 3 ; thanks for the correction jester!
bf01000000 mov edi, 1
31c0 xor eax, eax
e9d8ffffff jmp loc.imp.write
Run Code Online (Sandbox Code Playgroud)
我不是到编译器的开发,但由于移动到这些寄存器的每一个值是恒定的和已知的编译时间,我很好奇,为什么不GCC使用dl,dil和al来代替.也许有人会说,此功能不会让任何性能上的差异,但有一个在之间的可执行文件的大小有很大的区别mov $1, %rax => b801000000,并mov $1, %al => b001当我们谈论数千寄存器的程序访问.如果软件的优雅部分不仅体积小,它确实会对性能产生影响.
有人可以解释为什么"海湾合作委员会决定"它无所谓?
如果负载与两个早期存储重叠(并且负载未完全包含在最早的存储中),现代Intel或AMD x86实现是否可以从两个存储转发以满足负载?
例如,请考虑以下顺序:
mov [rdx + 0], eax
mov [rdx + 2], eax
mov ax, [rdx + 1]
Run Code Online (Sandbox Code Playgroud)
最后的2字节加载从前一个存储区获取其第二个字节,但是它之前的存储区的第一个字节.这个负载可以存储转发,还是需要等到两个先前的存储都提交给L1?
请注意,通过存储转发,我包括任何可以满足仍然存储在缓冲区中的存储的读取的机制,而不是等待它们提交到L1,即使它是一个比最好的情况"转发"更慢的路径.单店"案例.
assembly ×5
x86 ×4
x86-64 ×3
abi ×1
c++ ×1
concurrency ×1
gcc ×1
memory-model ×1
optimization ×1
performance ×1