好几次,我在matlab,fortran ......中遇到过这个术语......但是我从来没有找到解释是什么意思,它有什么作用?所以我在这里问,什么是矢量化,例如,"循环是矢量化的"是什么意思?
在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汇编的怪癖).
我想尝试使用SIMD指令编写atoi实现,包含在RapidJSON(C++ JSON 读 /写库)中.它目前在其他地方有一些SSE2和SSE4.2优化.
如果是速度增益,atoi
则可以并行执行多个结果.字符串最初来自JSON数据的缓冲区,因此多atoi函数将不得不进行任何所需的调配.
我想出的算法如下:
我的目标是x86和x86-64架构.
我知道AVX2支持三个操作数Fused Multiply-Add,所以我将能够执行Sum = Number*有效数字+和.
那是我到目前为止的地方.
我的算法是否正确?有没有更好的办法?
是否有使用任何SIMD指令集的atoi参考实现?
64位Linux默认使用小内存模型,它将所有代码和静态数据置于2GB地址限制之下.这可确保您可以使用32位绝对地址.较旧版本的gcc使用静态数组的32位绝对地址,以便为相对地址计算保存额外的指令.但是,这不再有效.如果我尝试在汇编中创建一个32位的绝对地址,我会收到链接器错误:"在创建共享对象时,不能使用".data"重定位R_X86_64_32S;使用-fPIC重新编译".当然,此错误消息具有误导性,因为我没有创建共享对象,-fPIC也没有帮助.到目前为止我发现的是:gcc版本4.8.5对静态数组使用32位绝对地址,gcc版本6.3.0不使用.版本5可能也没有.binutils 2.24中的链接器允许32位绝对地址,而2.28则不允许.
这种变化的后果是必须重新编译旧库并破坏传统汇编代码.
现在我想问一下:这个改变是什么时候做的?它在某处记录了吗?是否有一个链接器选项,使其接受32位绝对地址?
任何人都可以告诉我纯粹的汇编代码以十进制格式显示寄存器中的值吗?请不要建议使用printf hack,然后使用gcc进行编译.
描述:
好吧,我做了一些研究和NASM的一些实验,并认为我可以使用c库中的printf函数来打印整数.我是通过使用GCC编译器编译目标文件来完成的,所有工作都很公平.
但是,我想要实现的是以十进制形式打印存储在任何寄存器中的值.
我做了一些研究,发现DOS命令行的中断向量021h可以显示字符串和字符,而2或9位于ah寄存器中,数据在dx中.
结论:
我找到的所有示例都没有显示如何在不使用C库的printf的情况下以十进制形式显示寄存器的内容值.有没有人知道如何在装配中这样做?
假设我在寄存器中有一个整数,我该如何打印?你能展示一个简单的示例代码吗?
我已经知道如何打印一个字符串,如"你好,世界".
我正在Linux上开发.
SSE没有提供一种以可变数量移动打包整数的方法(我可以使用任何AVX和更旧的指令).你只能做统一的轮班.我试图为向量中的每个整数实现的结果是这个.
i[0] = i[0] & 0b111111;
i[1] = (i[1]>>6) & 0b111111;
i[2] = (i[2]>>12) & 0b111111;
i[3] = (i[3]>>18) & 0b111111;
Run Code Online (Sandbox Code Playgroud)
本质上是尝试在每个整数中隔离不同的6位组.
那么什么是最佳解决方案?
我想到的事情:你可以模拟一个变量右移,左移和左移一致.我想过将打包的整数乘以不同的量(因此模拟左移).然后结果,你可以做一个统一的右移得到答案.这个问题我会用乘法的具体运会_mm_mullo_epi32
,其中有令人失望的等待时间(10个循环的Haswell),并给予我的程序那就要等待结果造成这个特殊的结果是下一个指令的依赖.总的来说,我认为这种方法只比蛮力方法快一点,后者是解包,使用标量指令进行移位,然后重新打包向量,我认为这需要大约20个周期.
使用以下命令在我的Mac计算机上运行此代码:
nasm -f macho64 -o max.a maximum.asm
Run Code Online (Sandbox Code Playgroud)
这是我尝试在计算机上运行的代码,该代码在数组中找到最大的数字。
section .data
data_items:
dd 3,67,34,222,45,75,54,34,44,33,22,11,66,0
section .text
global _start
_start:
mov edi, 0
mov eax, [data_items + edi*4]
mov ebx, eax
start_loop:
cmp eax, 0
je loop_exit
inc edi
mov eax, [data_items + edi*4]
cmp eax, ebx
jle start_loop
mov ebx, eax
jmp start_loop
loop_exit:
mov eax, 1
int 0x80
Run Code Online (Sandbox Code Playgroud)
错误:
maximum.asm:14: error: Mach-O 64-bit format does not support 32-bit absolute addresses
maximum.asm:21: error: Mach-O 64-bit format does not support 32-bit absolute …
Run Code Online (Sandbox Code Playgroud) 旨在提供高性能数字运算的 CPU 最终会采用某种向量指令集。基本上有两种:
SIMD。这在概念上很简单,例如,您不仅拥有一组 64 位寄存器及其上的操作,还拥有第二组 128 位寄存器,并且可以同时对两个 64 位值的短向量进行操作。它在实现中变得复杂,因为您还希望可以选择对四个 32 位值进行操作,然后新一代 CPU 提供 256 位向量,这需要一套全新的指令等。
较旧的 Cray 风格向量指令,其中向量一开始很大,例如 4096 位,但同时操作的元素数量是透明的,并且要在给定操作中使用的元素数量是指令参数。这个想法是,你预先减少一点复杂性,以避免以后出现复杂性。
有人认为选项 2 更好,并且这些论点似乎有道理,例如https://www.sigarch.org/simd-instructions-considered-harmful/
至少乍一看,选项 2 似乎可以完成选项 1 可以做的所有事情,而且更容易,而且总体上更好。
是否存在相反情况的工作负载?SIMD 指令在哪里可以完成 Cray 式向量无法完成的任务,或者可以更快或使用更少的代码完成任务?