问题标签 [mmx]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c - 为什么这个 C 函数以二进制补码形式返回 int 值?
我正在使用一个库,该库使用英特尔的 MMX 单指令、多数据 (SIMD) 指令集来加速整数数组的乘法。我正在使用的函数包含内联汇编,以使用 Intel 处理器中的 MMX SIMD 寄存器并执行乘法运算。
将两个整数数组与函数相乘后,我收到一个数组,其中包含不正确的整数值,应该为负数。但是,当将这些值转换为二进制时,我注意到整数表示 2 的补码中的正确值。整数应该是 16 位长。
更奇怪的是,当两个负整数相乘时,而不是一个正数一个负数,该函数返回一个整数值,当转换为二进制时,添加一个额外位作为最高有效位(将附加位标记到左侧二进制数)。该位的值为 1,但如果您忽略该位,其余位将正确显示预期值。
很难用语言来表达,所以让我举个例子:
我有三个 int 数组 A、B 和 C。
A = {-1, 4, 1, -1, 1, -2, -3, 7},
B = {-1, -1, -1, -1, -1, -1, -1, 1}
C = {0, 0, 0, 0, 0, 0, 0, 0}
当 A 和 B 相乘时,我希望
{1, -4, -1, 1, -1, 2, 3, 7}
存储在 C 中。
然而,在使用图书馆的功能后,我得到
{65537、65532、65535、65537、65535、65538、65539、7}
作为我对 C 的价值观。
二进制的第一个值 65537 是 10000000000000001。如果没有额外的第 17 位,这将等于 1,但即便如此,该值也应该是 1,而不是 65537。二进制的第二个值 65532 是 1111111111111100,它是 2 的补码为-4。这很好,但为什么这个值不只是-4。还要注意最后一个值 7。当不涉及负号时,该函数会给出预期形式的值。
内联程序集是为在 Microsoft Visual Studio 上编译而编写的,但我使用的是带有 -use-msasm 标志的英特尔 c/c++ 编译器。
这是功能代码:
和我打电话的一个例子。
最后一个参数 16 是 A 和 B 中组合的总元素数。
我正在使用的库是免费使用的,可以在https://www.ngs.noaa.gov/gps-toolbox/Heckler.htm找到
assembly - 为什么 xmm 逻辑移位不起作用?
我在注册时加载了一些内容xmm1
,假设它可以被视为
现在,我想在每个双字逻辑上向右移动 1 个字节,所以它最终是这样的:
我在英特尔文档中发现我可能正在寻找函数“psrld”:
然而,它并没有像我预期的那样工作,因为一开始的价值xmm1
是
然后,应用 后psrld xmm1, 1
,xmm1 的值为
这不是我想做的。我哪里错了?实现此目的的正确方法是什么?
x86 - 查询旧版 3DNow!指令系统
只是为了好玩,我正在查看3DNow 的旧版(已弃用)说明!由AMD 介绍,我试图了解它们是如何使用的。所有指令似乎都按照这种模式编码:
其中destinationRegister
= -destinationRegister
操作-source
例如,pfadd mm0, mmword ptr [rcx]
(0F 0F 01 9E
):
会将 2 个压缩浮点数从指向的内存添加rcx
到 2 个压缩浮点数,mm0
并将结果保存在mm0
.
所以看起来那些 3DNow 指令总是有一个mm
寄存器作为目标。
但是你应该如何从这些mm
寄存器中得到结果呢?
换句话说,没有mov mmword ptr [rcx], mm0
, 或mov rax, mm0
指令。
c - 使用 SIMD 右移 32 位压缩负数
我正在编写一些 SSE/AVX 代码,并且有一项任务是将压缩的有符号 32 位整数除以 2 的补码。当值为正时,此移位可以正常工作,但是由于移位了符号位,因此对于负值会产生错误的结果。
是否有任何 SIMD 操作可以让我移动保留符号位的位置?谢谢
c++ - 如何从 __m64 值的 lsb 创建一个 8 位掩码?
我有一个用例,其中我有一个位数组,每个位表示为 8 位整数,例如uint8_t data[] = {0,1,0,1,0,1,0,1};
我想通过仅提取每个值的 lsb 来创建一个整数。我知道使用int _mm_movemask_pi8 (__m64 a)
函数我可以创建一个掩码,但这个内在函数只需要一个字节的 msb 而不是 lsb。是否有类似的内在或有效方法来提取 lsb 以创建单个 8 位整数?
assembly - 无符号整数存储的 MMX 寄存器速度与堆栈
我正在考虑在纯汇编中实现 SHA3。SHA3 具有 17 个 64 位无符号整数的内部状态,但由于它使用的转换,如果我在寄存器中有 44 个这样的整数可用,则可以实现最佳情况。可能加上一个临时寄存器。在这种情况下,我将能够在寄存器中进行整个转换。
但这是不现实的,甚至可以一直优化到几个寄存器。尽管如此,更多可能更好,这取决于这个问题的答案。
我正在考虑至少使用 MMX 寄存器进行快速存储,即使我需要换成其他寄存器进行计算。但我担心那是古代建筑。
MMX 寄存器和 RAX 之间的数据传输是否会比在堆栈上索引 u64 并从可能是 L1 缓存的地方访问它们更快?或者即使是这样,除了我应该注意的速度考虑之外,是否还有隐藏的陷阱?我对一般情况感兴趣,所以即使在我的计算机上一个比另一个快,它可能仍然没有定论。
assembly - 将两个数组相互添加并将结果存储在 3 中的问题,不起作用
我使用 mmx 的汇编语言程序有问题。该程序声明了 3 个数组,然后将两个相加并将结果存储在 3 中。出了什么问题?
assembly - 使用 MMX 指令集计算 f(x)=2*(x^2)+5 饱和度,用于从二进制文件加载的 128 个大小为 2 字节的数字
我有这个问题,我需要使用 MMX 指令集计算函数 f(x)=2*(x^2)+5。我有两个问题。这是我现在的代码:
我的第一个问题是乘法指令。我使用哪个指令来进行饱和。首先,我虽然会有类似的指令,pmulsw
但似乎没有。pmulhw
保存 32 位结果的高 16 位。我找不到任何可以给出 16 位结果的指令。它是保存 32 位结果的唯一方法吗?
第二个问题是 printf。它不断给出分段错误,我不知道为什么。这是来自我的终端:
这是生成文件:
为了您的方便,这里有一个小 C 程序,它可以生成二进制文件以供阅读:
c++11 - bad_alloc 带有 unordered_map initializer_list 和 MMX 指令,可能堆损坏?
我bad_alloc
从下面用 gcc 编译的代码中得到了一个抛出(尝试 4.9.3、5.40 和 6.2)。gdb 告诉我它发生在 unordered_map 的 initalizer_list 的最后一行。如果我注释掉 mmx 指令_m_maskmovq
,则没有错误。同样,如果我注释掉 unordered_map 的初始化,这没有错误。只有在调用 mmx 指令并使用 initializer_list 初始化 unordered_map 时,我才能获得bad_alloc
. 如果我默认构造 unordered_map 并调用map.emplace(1,1)
也没有错误。我已经在具有 48 个内核(intel xeon)和 376 GB RAM 的 centos7 机器上以及在 Ubuntu WSL 下的戴尔笔记本电脑(intel core i7)上运行它,结果相同。这里发生了什么?MMX 指令是否破坏了堆?Valgrind 似乎没有发现任何有用的东西。
编译器命令和输出:
源代码(main.cpp):
更新:
_mm_empty() 解决方法确实修复了此示例。当使用一个线程执行向量指令而另一个线程使用 unordered_map 的多线程代码时,这似乎不是一个可行的解决方案。另一个有趣的点是,如果我对-O3
bad_alloc 进行优化,它就会消失。祈祷我们在生产过程中从未遇到过这个错误(畏缩)。
assembly - 有没有办法在 x86 上使用 MMX/SSE 减去压缩的无符号双字?
我一直在看 MMX/SSE,我想知道。有用于无符号字节和字的压缩饱和减法的指令,但不是双字。
有没有办法做我想做的事,或者如果没有,为什么没有?